1 #ifndef BGP_FLOW_SPEC_H
2 #define BGP_FLOW_SPEC_H
3
4 #include <stdint.h>
5 #include <string>
6 #include <vector>
7
8 #include "fastnetmon_types.h"
9 #include "fast_library.h"
10
11 // Helper for serialization by comma
12 template <typename T>
serialize_vector_by_string(const std::vector<T> vect,std::string delimiter)13 std::string serialize_vector_by_string(const std::vector<T> vect, std::string delimiter) {
14 std::ostringstream output_buffer;
15
16 std::copy(vect.begin(), vect.end() - 1, std::ostream_iterator<T>(output_buffer, delimiter.c_str()));
17 output_buffer << vect.back();
18
19 return output_buffer.str();
20 }
21
22 template <typename T>
serialize_vector_by_string_with_prefix(const std::vector<T> vect,std::string delimiter,std::string prefix)23 std::string serialize_vector_by_string_with_prefix(const std::vector<T> vect, std::string delimiter, std::string prefix) {
24 std::vector<std::string> elements_with_prefix;
25
26 for (typename std::vector<T>::const_iterator itr = vect.begin(); itr != vect.end(); ++itr) {
27 elements_with_prefix.push_back(prefix + convert_int_to_string(*itr));
28 }
29
30 return serialize_vector_by_string<std::string>(elements_with_prefix, delimiter);
31 }
32
33 // All possible values for BGP Flow Spec fragmentation field
34 enum flow_spec_fragmentation_types_t {
35 FLOW_SPEC_DONT_FRAGMENT,
36 FLOW_SPEC_IS_A_FRAGMENT,
37 FLOW_SPEC_FIRST_FRAGMENT,
38 FLOW_SPEC_LAST_FRAGMENT,
39 FLOW_NOT_A_FRAGMENT,
40 };
41
42 // TCP flags for Flow Spec
43 enum flow_spec_tcp_flags_t {
44 FLOW_TCP_FLAG_SYN,
45 FLOW_TCP_FLAG_FIN,
46 FLOW_TCP_FLAG_URG,
47 FLOW_TCP_FLAG_ACK,
48 FLOW_TCP_FLAG_PSH,
49 FLOW_TCP_FLAG_RST,
50 };
51
52 // Flow spec actions
53 enum bgp_flow_spec_action_types_t {
54 FLOW_SPEC_ACTION_DISCARD,
55 FLOW_SPEC_ACTION_ACCEPT,
56 FLOW_SPEC_ACTION_RATE_LIMIT,
57 // TBD
58 };
59
60 enum bgp_flow_spec_protocol_t {
61 FLOW_SPEC_PROTOCOL_UDP,
62 FLOW_SPEC_PROTOCOL_TCP,
63 FLOW_SPEC_PROTOCOL_ICMP,
64 };
65
66 // Enable custom casts from our own types
67 std::ostream &operator<<(std::ostream &os, bgp_flow_spec_protocol_t const &protocol) {
68 if (protocol == FLOW_SPEC_PROTOCOL_UDP) {
69 return os << "udp";
70 } else if (protocol == FLOW_SPEC_PROTOCOL_TCP) {
71 return os << "tcp";
72 } else if (protocol == FLOW_SPEC_PROTOCOL_ICMP) {
73 return os << "icmp";
74 } else {
75 return os;
76 }
77 }
78
79 std::ostream &operator<<(std::ostream &os, flow_spec_fragmentation_types_t const &fragment_flag) {
80 // Nice docs here: https://github.com/Exa-Networks/exabgp/blob/71157d560096ec20084cf96cfe0f60203721e93b/lib/exabgp/protocol/ip/fragment.py
81
82 if (fragment_flag == FLOW_SPEC_DONT_FRAGMENT) {
83 return os << "dont-fragment";
84 } else if (fragment_flag == FLOW_SPEC_IS_A_FRAGMENT) {
85 return os << "is-fragment";
86 } else if (fragment_flag == FLOW_SPEC_FIRST_FRAGMENT) {
87 return os << "first-fragment";
88 } else if (fragment_flag == FLOW_SPEC_LAST_FRAGMENT) {
89 return os << "last-fragment";
90 } else if (fragment_flag == FLOW_NOT_A_FRAGMENT) {
91 return os << "not-a-fragment";
92 } else {
93 return os;
94 }
95 }
96
97 std::ostream &operator<<(std::ostream &os, flow_spec_tcp_flags_t const &tcp_flag) {
98 if (tcp_flag == FLOW_TCP_FLAG_SYN) {
99 return os << "syn";
100 } else if (tcp_flag == FLOW_TCP_FLAG_ACK) {
101 return os << "ack";
102 } else if (tcp_flag == FLOW_TCP_FLAG_FIN) {
103 return os << "fin";
104 } else if (tcp_flag == FLOW_TCP_FLAG_URG) {
105 return os << "urgent";
106 } else if (tcp_flag == FLOW_TCP_FLAG_PSH) {
107 return os << "push";
108 } else if(tcp_flag == FLOW_TCP_FLAG_RST) {
109 return os << "rst";
110 } else {
111 return os;
112 }
113 }
114
115 class bgp_flow_spec_action_t {
116 public:
bgp_flow_spec_action_t()117 bgp_flow_spec_action_t() {
118 this->action_type = FLOW_SPEC_ACTION_ACCEPT;
119 this->rate_limit = 9600;
120
121 sentence_separator = ";";
122 }
123
set_type(bgp_flow_spec_action_types_t action_type)124 void set_type(bgp_flow_spec_action_types_t action_type) {
125 this->action_type = action_type;
126 }
127
set_rate_limit(unsigned int rate_limit)128 void set_rate_limit(unsigned int rate_limit) {
129 this->rate_limit = rate_limit;
130 }
131
set_sentence_separator(std::string sentence_separator)132 void set_sentence_separator(std::string sentence_separator) {
133 this->sentence_separator = sentence_separator;
134 }
135
serialize()136 std::string serialize() {
137 if (this->action_type == FLOW_SPEC_ACTION_ACCEPT) {
138 return "accept" + sentence_separator;
139 } else if (this->action_type == FLOW_SPEC_ACTION_DISCARD) {
140 return "discard" + sentence_separator;
141 } else if (this->action_type == FLOW_SPEC_ACTION_RATE_LIMIT) {
142 return "rate-limit " + convert_int_to_string(this->rate_limit) + sentence_separator;
143 }
144 }
145 private:
146 bgp_flow_spec_action_types_t action_type;
147 unsigned int rate_limit;
148 std::string sentence_separator;
149 // TBD
150
151 // Community, rate-limit value
152 };
153
154 // We do not use < and > operators at all, sorry
155 class flow_spec_rule_t {
156 public:
flow_spec_rule_t()157 flow_spec_rule_t() {
158 // We should explidictly initialize it!
159 source_subnet_used = false;
160 destination_subnet_used = false;
161 }
162
announce_is_correct()163 bool announce_is_correct() {
164 if (source_subnet_used || destination_subnet_used) {
165 return true;
166 } else {
167 return false;
168 }
169 }
170
set_source_subnet(subnet_t source_subnet)171 void set_source_subnet(subnet_t source_subnet) {
172 this->source_subnet = source_subnet;
173 this->source_subnet_used = true;
174 }
175
set_destination_subnet(subnet_t destination_subnet)176 void set_destination_subnet(subnet_t destination_subnet) {
177 this->destination_subnet = destination_subnet;
178 this->destination_subnet_used = true;
179 }
180
add_source_port(uint16_t source_port)181 void add_source_port(uint16_t source_port) {
182 this->source_ports.push_back(source_port);
183 }
184
add_destination_port(uint16_t destination_port)185 void add_destination_port(uint16_t destination_port) {
186 this->destination_ports.push_back(destination_port);
187 }
188
add_packet_length(uint16_t packet_length)189 void add_packet_length(uint16_t packet_length) {
190 this->packet_lengths.push_back(packet_length);
191 }
192
add_protocol(bgp_flow_spec_protocol_t protocol)193 void add_protocol(bgp_flow_spec_protocol_t protocol) {
194 this->protocols.push_back(protocol);
195 }
196
197 /*
198 std::string icmp_flags;
199 bool icmp_flags_used;
200
201 std::string icmp_type;
202 bool icmp_type_used;
203
204 std::string dscp;
205 bool dscp_used;
206 */
207
add_fragmentation_flag(flow_spec_fragmentation_types_t flag)208 void add_fragmentation_flag(flow_spec_fragmentation_types_t flag) {
209 this->fragmentation_flags.push_back(flag);
210 }
211
add_tcp_flag(flow_spec_tcp_flags_t flag)212 void add_tcp_flag(flow_spec_tcp_flags_t flag) {
213 this->tcp_flags.push_back(flag);
214 }
215
set_action(bgp_flow_spec_action_t action)216 void set_action(bgp_flow_spec_action_t action) {
217 this->action = action;
218 }
219 protected:
220 // Only IPv4 supported
221 subnet_t source_subnet;
222 bool source_subnet_used;
223
224 subnet_t destination_subnet;
225 bool destination_subnet_used;
226
227 std::vector<uint16_t> source_ports;
228 std::vector<uint16_t> destination_ports;
229 std::vector<uint16_t> packet_lengths;
230 std::vector<bgp_flow_spec_protocol_t> protocols;
231 std::vector<flow_spec_fragmentation_types_t> fragmentation_flags;
232 std::vector<flow_spec_tcp_flags_t> tcp_flags;
233
234 bgp_flow_spec_action_t action;
235 };
236
237 class exabgp_flow_spec_rule_t : public flow_spec_rule_t {
238 public:
exabgp_flow_spec_rule_t()239 exabgp_flow_spec_rule_t() {
240 four_spaces = " ";
241 sentence_separator = ";";
242
243 this->enabled_indents = true;
244 this->enble_block_headers = true;
245 }
246
disable_indents()247 void disable_indents() {
248 enabled_indents = false;
249 }
250
serialize_source_ports()251 std::string serialize_source_ports() {
252 std::ostringstream output_buffer;
253
254 output_buffer << "source-port [ " << serialize_vector_by_string_with_prefix<uint16_t>(this->source_ports, " ", "=") << " ]" << sentence_separator;
255
256 return output_buffer.str();
257 }
258
serialize_destination_ports()259 std::string serialize_destination_ports() {
260 std::ostringstream output_buffer;
261
262 output_buffer << "destination-port [ " << serialize_vector_by_string_with_prefix<uint16_t>(this->destination_ports, " ", "=") << " ]" << sentence_separator;
263
264 return output_buffer.str();
265 }
266
serialize_packet_lengths()267 std::string serialize_packet_lengths() {
268 std::ostringstream output_buffer;
269
270 output_buffer << "packet-length [ " << serialize_vector_by_string_with_prefix<uint16_t>(this->packet_lengths, " ", "=") << " ]" << sentence_separator;
271
272 return output_buffer.str();
273 }
274
275
serialize_protocols()276 std::string serialize_protocols() {
277 std::ostringstream output_buffer;
278
279 output_buffer << "protocol [ " << serialize_vector_by_string(this->protocols, " ") << " ]" << sentence_separator;
280
281 return output_buffer.str();
282 }
serialize_fragmentation_flags()283 std::string serialize_fragmentation_flags() {
284 std::ostringstream output_buffer;
285
286 output_buffer << "fragment [ " << serialize_vector_by_string(this->fragmentation_flags, " ") << " ]" << sentence_separator;
287
288 return output_buffer.str();
289 }
290
serialize_tcp_flags()291 std::string serialize_tcp_flags() {
292 std::ostringstream output_buffer;
293
294 output_buffer << "tcp-flags [ " << serialize_vector_by_string(this->tcp_flags, " ") << " ]" << sentence_separator;
295
296 return output_buffer.str();
297 }
298
serialize_source_subnet()299 std::string serialize_source_subnet() {
300 return "source " + convert_subnet_to_string(this->source_subnet) + sentence_separator;
301 }
302
serialize_destination_subnet()303 std::string serialize_destination_subnet() {
304 return "destination " + convert_subnet_to_string(this->destination_subnet) + sentence_separator;
305 }
306
307 // More details regarding format: https://github.com/Exa-Networks/exabgp/blob/master/qa/conf/api-flow.run
308 // https://plus.google.com/+ThomasMangin/posts/bL6w16BXcJ4
309 // This format is INCOMPATIBLE with ExaBGP v3, please be careful!
serialize_single_line_exabgp_v4_configuration()310 std::string serialize_single_line_exabgp_v4_configuration() {
311 this->enabled_indents = false;
312 this->enble_block_headers = false;
313 sentence_separator = " ";
314
315 return "flow route " + this->serialize_match() + this->serialize_then();
316
317 sentence_separator = ";";
318 this->enabled_indents = true;
319 this->enble_block_headers = true;
320 }
321
serialize_complete_exabgp_configuration()322 std::string serialize_complete_exabgp_configuration() {
323 std::ostringstream buffer;
324
325 buffer << "neighbor 127.0.0.1 {" << "\n"
326 << four_spaces << "router-id 1.2.3.4;" << "\n"
327 << four_spaces << "local-address 127.0.0.1;" << "\n"
328 << four_spaces << "local-as 1;" << "\n"
329 << four_spaces << "peer-as 1;" << "\n"
330 << four_spaces << "group-updates false;" << "\n\n";
331
332 buffer << four_spaces << "family {" << "\n"
333 << four_spaces << four_spaces << "ipv4 flow;" << "\n"
334 << four_spaces << four_spaces << "ipv6 flow;" << "\n"
335 << four_spaces << "}" << "\n";
336
337 buffer << "flow {" << "\n";
338 buffer << this->serialize();
339 buffer << "}" << "\n";
340
341 buffer << "}" << "\n";
342
343 return buffer.str();
344 }
345
serialize()346 std::string serialize() {
347 std::ostringstream buffer;
348
349 buffer << "route {";
350
351 if (enabled_indents) {
352 buffer << "\n";
353 }
354
355 buffer << this->serialize_match();
356 buffer << this->serialize_then();
357
358 if (enabled_indents) {
359 buffer << "\n";
360 }
361
362 buffer << "}";
363
364 if (enabled_indents) {
365 buffer << "\n";
366 }
367
368 return buffer.str();
369 }
370
serialize_match()371 std::string serialize_match() {
372 std::ostringstream buffer;
373
374 if (enabled_indents) {
375 buffer << four_spaces;
376 }
377
378 if (enble_block_headers) {
379 buffer << "match {";
380 }
381
382 if (enabled_indents) {
383 buffer << "\n";
384 }
385
386 // Match block
387 if (this->source_subnet_used) {
388 if (enabled_indents) {
389 buffer << four_spaces << four_spaces;
390 }
391
392 buffer << serialize_source_subnet();
393
394 if (enabled_indents) {
395 buffer << "\n";
396 }
397 }
398
399 if (this->destination_subnet_used) {
400 if (enabled_indents) {
401 buffer << four_spaces << four_spaces;
402 }
403
404 buffer << serialize_destination_subnet();
405
406 if (enabled_indents) {
407 buffer << "\n";
408 }
409 }
410
411 if (!this->protocols.empty()) {
412 if (enabled_indents) {
413 buffer << four_spaces << four_spaces;
414 }
415
416 buffer << this->serialize_protocols();
417
418 if (enabled_indents) {
419 buffer << "\n";
420 }
421 }
422
423 // If we have TCP in protocols list explicitly, we add flags
424 if (find(this->protocols.begin(), this->protocols.end(), FLOW_SPEC_PROTOCOL_TCP)
425 != this->protocols.end() ) {
426
427 if (!this->tcp_flags.empty()) {
428 if (enabled_indents) {
429 buffer << four_spaces << four_spaces;
430 }
431
432 buffer << this->serialize_tcp_flags();
433
434 if (enabled_indents) {
435 buffer << "\n";
436 }
437 }
438 }
439
440 if (!this->source_ports.empty()) {
441 if (enabled_indents) {
442 buffer << four_spaces << four_spaces;
443 }
444
445 buffer << this->serialize_source_ports();
446
447 if (enabled_indents) {
448 buffer << "\n";
449 }
450 }
451
452 if (!this->destination_ports.empty()) {
453 if (enabled_indents) {
454 buffer << four_spaces << four_spaces;
455 }
456
457 buffer << this->serialize_destination_ports();
458
459 if (enabled_indents) {
460 buffer << "\n";
461 }
462 }
463
464 if (!this->packet_lengths.empty()) {
465 if (enabled_indents) {
466 buffer << four_spaces << four_spaces;
467 }
468
469 buffer << this->serialize_packet_lengths();
470
471 if (enabled_indents) {
472 buffer << "\n";
473 }
474 }
475
476 if (!this->fragmentation_flags.empty()) {
477 if (enabled_indents) {
478 buffer << four_spaces << four_spaces;
479 }
480
481 buffer << this->serialize_fragmentation_flags();
482
483 if (enabled_indents) {
484 buffer << "\n";
485 }
486 }
487
488 // Match block end
489 if (enabled_indents) {
490 buffer << four_spaces;
491 }
492
493 if (enble_block_headers) {
494 buffer << "}";
495 }
496
497 return buffer.str();
498 }
499
serialize_then()500 std::string serialize_then() {
501 std::ostringstream buffer;
502
503 if (enabled_indents) {
504 buffer << "\n" << four_spaces;
505 }
506
507 if (enble_block_headers) {
508 buffer << "then {";
509 }
510
511 if (enabled_indents) {
512 buffer << "\n";
513 buffer << four_spaces << four_spaces;
514 }
515
516 // Set same sentence separator as in main class
517 this->action.set_sentence_separator(this->sentence_separator);
518
519 buffer << this->action.serialize();
520
521 if (enabled_indents) {
522 buffer << "\n";
523 buffer << four_spaces;
524 }
525
526 if (enble_block_headers) {
527 buffer << "}";
528 }
529
530 return buffer.str();
531 }
532
533 private:
534 std::string four_spaces;
535 bool enabled_indents;
536 bool enble_block_headers;
537 std::string sentence_separator;
538 };
539
exabgp_flow_spec_rule_ban_manage(std::string action,flow_spec_rule_t flow_spec_rule)540 void exabgp_flow_spec_rule_ban_manage(std::string action, flow_spec_rule_t flow_spec_rule) {
541 // "announce flow route {\\n match {\\n source 10.0.0.1/32;\\nsource-port =" + str(i) +
542 // ";\\n destination 1.2.3.4/32;\\n }\\n then {\\n discard;\\n }\\n }\\n\n")
543 }
544
545
546 #endif
547