-
Notifications
You must be signed in to change notification settings - Fork 1
/
encode.go
253 lines (211 loc) · 4.99 KB
/
encode.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
package main
import (
"bytes"
"encoding/binary"
"net"
)
const (
bgpVersion = 4
// BGP message types
open = 1
update = 2
notification = 3
keepalive = 4
refresh = 5
// as_path values
asSet = 1
asSequence = 2
// Error codes
headerError = 1
openError = 2
updateError = 3
holdTimeExpired = 4
fsmError = 5
cease = 6
// min and max BGP message size in bytes
minMessage = 19
maxMessage = 4096
// AFI/SAFI
afiIPv4 uint16 = 1
afiIPv6 uint16 = 2
safiUnicast uint8 = 1
)
type bgpid [4]byte
type ipv4Address []byte
type ipv6Address []byte
type twoByteLength [2]byte
type v4Addr struct {
Mask uint8
Prefix net.IP
ID uint32
}
type v6Addr struct {
Mask uint8
Prefix net.IP
ID uint32
}
type msgOpen struct {
Version uint8
ASN uint16
HoldTime uint16
BGPID bgpid
ParamLen uint8
}
// Must be a better way...
func sizeOfStruct(i interface{}) int {
buf := &bytes.Buffer{}
binary.Write(buf, binary.BigEndian, i)
return len(buf.Bytes())
}
// BGP packets start with 16 bytes of FF
func getMarker(b *bytes.Buffer) {
// Always start a new packet by ensuring the buffer is flushed.
b.Reset()
b.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
}
// Keepalives are minimum size with a type code of keepalive
func (p *peer) createKeepAlive() {
getMarker(p.out)
k := []byte{0, 0, keepalive}
p.out.Write(k)
}
// Encode packet over the wire
func (p *peer) encodeOutgoing() {
// Set size
b := p.out.Bytes()
setSizeOfMessage(&b)
//log.Printf("Will encode the following...")
//log.Printf("%#v\n", b)
binary.Write(p.conn, binary.BigEndian, b)
}
func setSizeOfMessage(b *[]byte) {
s := uint16ToByte(uint16(len(*b)))
(*b)[16] = s[0]
(*b)[17] = s[1]
}
func (p *peer) createOpen() {
getMarker(p.out)
// Need to convert both ASN and Holdtime to [2]byte. Another function?
// First two bytes zero as they will be updated to contain the length later
p.out.Write([]byte{0, 0, open, bgpVersion})
p.out.Write(getOpenASN(p.asn))
p.out.Write(uint16ToByte(p.holdtime))
p.out.Write(p.rid[:])
// Add parameters
param, len := createParameters(&p.param, p.asn)
p.out.Write([]byte{len})
p.out.Write(param)
}
func getOpenASN(asn uint16) []byte {
// If 32bit ASN, open message will contain AS23456
if asn == 23456 {
return []byte{0x5b, 0xa0}
}
return uint16ToByte(asn)
}
func uint16ToByte(i uint16) []byte {
a := i / 256
b := i % 256
return []byte{byte(a), byte(b)}
}
func uint32ToByte(i uint32) []byte {
a := i / 16777216
b := i / 65536
c := i / 256
d := i % 256
return []byte{byte(a), byte(b), byte(c), byte(d)}
}
//TODO: Buggy, test!
func createParameters(p *parameters, asn uint16) ([]byte, uint8) {
var param []byte
initial := []byte{
2, // Parameter Type
0, // Length. Adjusted at the end
capRefresh,
0, // refresh is always size 0
cap4Byte,
4, // 4 byte ASN is always size 4
}
param = append(param, initial...)
// TODO: Test this both on real router and test code
if isASN32(p.ASN32) {
param = append(param, p.ASN32[:]...)
} else {
param = append(param, 0, 0)
param = append(param, uint16ToByte(asn)...)
}
// Only advertise the AF family that the peer sends us
for _, a := range p.AddrFamilies {
if isIPv4Unicast(a) {
ip4 := createIPv4Cap()
param = append(param, ip4...)
}
if isIPv6Unicast(a) {
ip6 := createIPv6Cap()
param = append(param, ip6...)
}
}
for _, a := range p.AddPath {
if isIPv4Unicast(a) {
ip4 := createIPv4AddPath()
param = append(param, ip4...)
}
if isIPv6Unicast(a) {
ip6 := createIPv6AddPath()
param = append(param, ip6...)
}
}
// Insert size of parameters. This is the total size minus the parameter type and size bytes
param[1] = byte(len(param) - 2)
return param, uint8(len(param))
}
// This isn't great
func createIPv4Cap() []byte {
// Unknown numbers!
return []byte{capMpBgp, 4, 0, 1, 0, 1}
}
func createIPv6Cap() []byte {
// Unknown numbers!
return []byte{capMpBgp, 4, 0, 2, 0, 1}
}
func createIPv4AddPath() []byte {
// TODO: All these should be in a single function and documented.
// Last digit is 1 because I only support receiving multiple paths
return []byte{capAddPath, 4, 0, 1, 1, 1}
}
func createIPv6AddPath() []byte {
// TODO: All these should be in a single function and documented.
// Last digit is 1 because I only support receiving multiple paths
return []byte{capAddPath, 4, 0, 2, 1, 1}
}
type parameterHeader struct {
Type uint8
Length uint8
}
type msgCapability struct {
Code uint8
Length uint8
}
type optGres struct {
Restart uint8
Time uint8
}
type opt4Byte struct {
ASN uint32
}
type msgNotification struct {
Code uint8
Subcode uint8
}
func (t twoByteLength) toUint16() uint16 {
return uint16(int(t[0])*256 + int(t[1]))
}
func (t twoByteLength) toInt64() int64 {
return int64(t.toUint16())
}
// If ASN field is all zeros, there is no 32bit ASN
func isASN32(asn [4]byte) bool {
empty := [4]byte{}
return !bytes.Equal(empty[:], asn[:])
}