File: flow_event.go

package info (click to toggle)
fever 1.0.5-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 512 kB
  • sloc: makefile: 17; sh: 12
file content (279 lines) | stat: -rw-r--r-- 5,546 bytes parent folder | download | duplicates (5)
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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
package types

// DCSO FEVER
// Copyright (c) 2017, 2018, DCSO GmbH

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"net"
	"time"
)

// FlowEvent stores the meta-data of a flow event in a compact, binary form.
type FlowEvent struct {
	Timestamp     uint64
	Format        byte
	SrcIP         []byte
	DestIP        []byte
	SrcPort       uint16
	DestPort      uint16
	BytesToServer uint32
	BytesToClient uint32
	PktsToServer  uint32
	PktsToClient  uint32
	Flags         uint16
}

// FlowEventFlags defines various flags for use in FlowEvent.Flags (e.g. the protocol).
var FlowEventFlags = map[string]uint16{
	"TCP": 1 << 0,
	"UDP": 1 << 1,
}

var maxBytes = int64(^uint32(0))

func parseIP(stringIP string) ([]byte, error) {
	ip := net.ParseIP(stringIP)
	if ip == nil {
		return nil, errors.New("invalid IP")
	}
	ipv4 := ip.To4()
	if ipv4 == nil {
		//this is an IPv6 address
		reverseIP(ip)
		return ip, nil
	}
	//this is an IPv4 address
	reverseIP(ipv4)
	return ipv4, nil
}

func reverseIP(b []byte) {
	for i := 0; i < len(b); i++ {
		b[i], b[len(b)-i-1] = b[len(b)-i-1], b[i]
	}
}

// FromEntry populates a FlowEvent using an Entry
func (fe *FlowEvent) FromEntry(e *Entry) error {
	ts, err := time.Parse(SuricataTimestampFormat, e.Timestamp)
	if err != nil {
		return err
	}

	srcIP, err := parseIP(e.SrcIP)
	if err != nil {
		return err
	}

	destIP, err := parseIP(e.DestIP)
	if err != nil {
		return err
	}

	flags := uint16(0)

	if e.Proto == "TCP" {
		flags |= FlowEventFlags["TCP"]
	}

	if e.Proto == "UDP" {
		flags |= FlowEventFlags["UDP"]
	}

	fe.Timestamp = uint64(ts.UnixNano())
	fe.SrcIP = srcIP
	fe.SrcPort = uint16(e.SrcPort)
	fe.DestIP = destIP
	fe.DestPort = uint16(e.DestPort)

	fe.Format = 1

	if len(srcIP) == 16 {
		fe.Format |= 1 << 1
	}

	fe.Format |= 1 << 2 //bits 3,4,5 and 6 mark the version (currently 1)

	if len(srcIP) != len(destIP) {
		return fmt.Errorf("source and destination IPS have different lengths O.o")
	}

	if e.BytesToServer > maxBytes {
		return errors.New("BytesToServer is too large")
	}

	if e.BytesToClient > maxBytes {
		return errors.New("BytesToClient is too large")
	}

	if e.PktsToServer > maxBytes {
		return errors.New("PktsToServer is too large")
	}

	if e.PktsToClient > maxBytes {
		return errors.New("PktsToClient is too large")
	}

	fe.BytesToServer = uint32(e.BytesToServer)
	fe.BytesToClient = uint32(e.BytesToClient)
	fe.PktsToServer = uint32(e.PktsToServer)
	fe.PktsToClient = uint32(e.PktsToClient)
	fe.Flags = flags

	return nil

}

// Unmarshal reads a FlowEvent from an io.Reader.
func (fe *FlowEvent) Unmarshal(reader io.Reader) error {

	bs1 := make([]byte, 1)
	bs2 := make([]byte, 2)
	bs4 := make([]byte, 4)
	bs8 := make([]byte, 8)

	//format
	if _, err := io.ReadFull(reader, bs1); err != nil {
		return err
	}
	fe.Format = bs1[0]
	if fe.Format&0x01 != 0x01 {
		return fmt.Errorf("invalid format byte (should start with a 1)")
	}

	isIPv6 := (fe.Format & 0x02) == 0x02

	//timestamp
	if _, err := io.ReadFull(reader, bs8); err != nil {
		return err
	}
	fe.Timestamp = binary.LittleEndian.Uint64(bs8)

	//src ip
	if isIPv6 {
		fe.SrcIP = make([]byte, 4*4)
		if _, err := io.ReadFull(reader, fe.SrcIP); err != nil {
			return err
		}
	} else {
		fe.SrcIP = make([]byte, 4)
		if _, err := io.ReadFull(reader, fe.SrcIP); err != nil {
			return err
		}
	}

	//src port
	if _, err := io.ReadFull(reader, bs2); err != nil {
		return err
	}
	fe.SrcPort = binary.LittleEndian.Uint16(bs2)

	//dest ip
	if isIPv6 {
		fe.DestIP = make([]byte, 4*4)
		if _, err := io.ReadFull(reader, fe.DestIP); err != nil {
			return err
		}
	} else {
		fe.DestIP = make([]byte, 4)
		if _, err := io.ReadFull(reader, fe.DestIP); err != nil {
			return err
		}
	}

	//dest port
	if _, err := io.ReadFull(reader, bs2); err != nil {
		return err
	}
	fe.DestPort = binary.LittleEndian.Uint16(bs2)

	//PktsToServer
	if _, err := io.ReadFull(reader, bs4); err != nil {
		return err
	}
	fe.PktsToServer = binary.LittleEndian.Uint32(bs4)

	//PktsToClient
	if _, err := io.ReadFull(reader, bs4); err != nil {
		return err
	}
	fe.PktsToClient = binary.LittleEndian.Uint32(bs4)

	//BytesToServer
	if _, err := io.ReadFull(reader, bs4); err != nil {
		return err
	}
	fe.BytesToServer = binary.LittleEndian.Uint32(bs4)

	//BytesToClient
	if _, err := io.ReadFull(reader, bs4); err != nil {
		return err
	}
	fe.BytesToClient = binary.LittleEndian.Uint32(bs4)

	//Flags
	if _, err := io.ReadFull(reader, bs2); err != nil {
		return err
	}
	fe.Flags = binary.LittleEndian.Uint16(bs2)

	return nil
}

// Marshal writes a FlowEvent to an io.Writer.
func (fe *FlowEvent) Marshal(writer io.Writer) error {

	bs1 := make([]byte, 1)
	bs2 := make([]byte, 2)
	bs4 := make([]byte, 4)
	bs8 := make([]byte, 8)

	//format
	bs1[0] = fe.Format
	writer.Write(bs1)

	//timestamp
	binary.LittleEndian.PutUint64(bs8, fe.Timestamp)
	writer.Write(bs8)

	//src ip
	writer.Write(fe.SrcIP)

	//src port
	binary.LittleEndian.PutUint16(bs2, fe.SrcPort)
	writer.Write(bs2)

	//dest ip
	writer.Write(fe.DestIP)

	//dest port
	binary.LittleEndian.PutUint16(bs2, fe.DestPort)
	writer.Write(bs2)

	//PktsToServer
	binary.LittleEndian.PutUint32(bs4, fe.PktsToServer)
	writer.Write(bs4)

	//PktsToClient
	binary.LittleEndian.PutUint32(bs4, fe.PktsToClient)
	writer.Write(bs4)

	//BytesToServer
	binary.LittleEndian.PutUint32(bs4, fe.BytesToServer)
	writer.Write(bs4)

	//BytesToClient
	binary.LittleEndian.PutUint32(bs4, fe.BytesToClient)
	writer.Write(bs4)

	//Flags
	binary.LittleEndian.PutUint16(bs2, fe.Flags)
	writer.Write(bs2)

	return nil

}