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