]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_flowspec_util.c
bgpd: fix display with flowspec tcp flags option
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
1 /* BGP FlowSpec Utilities
2 * Portions:
3 * Copyright (C) 2017 ChinaTelecom SDN Group
4 * Copyright (C) 2018 6WIND
5 *
6 * FRRouting is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * FRRouting is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "zebra.h"
22
23 #include "prefix.h"
24
25 #include "bgp_table.h"
26 #include "bgp_flowspec_util.h"
27 #include "bgp_flowspec_private.h"
28 #include "bgp_pbr.h"
29
30 static void hex2bin(uint8_t *hex, int *bin)
31 {
32 int remainder = *hex;
33 int i = 0;
34
35 while (remainder >= 1 && i < 8) {
36 bin[7-i] = remainder % 2;
37 remainder = remainder / 2;
38 i++;
39 }
40 for (; i < 8; i++)
41 bin[7-i] = 0;
42 }
43
44 static int hexstr2num(uint8_t *hexstr, int len)
45 {
46 int i = 0;
47 int num = 0;
48
49 for (i = 0; i < len; i++)
50 num = hexstr[i] + 16*16*num;
51 return num;
52 }
53
54 /* call bgp_flowspec_op_decode
55 * returns offset
56 */
57 static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len,
58 struct bgp_pbr_match_val *mval,
59 uint8_t *match_num, int *error)
60 {
61 int ret;
62
63 ret = bgp_flowspec_op_decode(
64 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
65 nlri_content,
66 len,
67 mval, error);
68 if (*error < 0)
69 zlog_err("%s: flowspec_op_decode error %d",
70 __func__, *error);
71 else
72 *match_num = *error;
73 return ret;
74 }
75
76 static bool bgp_flowspec_contains_prefix(struct prefix *pfs,
77 struct prefix *input,
78 int prefix_check)
79 {
80 uint32_t offset = 0;
81 int type;
82 int ret = 0, error = 0;
83 uint8_t *nlri_content = (uint8_t *)pfs->u.prefix_flowspec.ptr;
84 size_t len = pfs->u.prefix_flowspec.prefixlen;
85 struct prefix compare;
86
87 error = 0;
88 while (offset < len-1 && error >= 0) {
89 type = nlri_content[offset];
90 offset++;
91 switch (type) {
92 case FLOWSPEC_DEST_PREFIX:
93 case FLOWSPEC_SRC_PREFIX:
94 memset(&compare, 0, sizeof(struct prefix));
95 ret = bgp_flowspec_ip_address(
96 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
97 nlri_content+offset,
98 len - offset,
99 &compare, &error);
100 if (ret <= 0)
101 break;
102 if (prefix_check &&
103 compare.prefixlen != input->prefixlen)
104 break;
105 if (compare.family != input->family)
106 break;
107 if ((input->family == AF_INET) &&
108 IPV4_ADDR_SAME(&input->u.prefix4,
109 &compare.u.prefix4))
110 return true;
111 if ((input->family == AF_INET6) &&
112 IPV6_ADDR_SAME(&input->u.prefix6.s6_addr,
113 &compare.u.prefix6.s6_addr))
114 return true;
115 break;
116 case FLOWSPEC_IP_PROTOCOL:
117 case FLOWSPEC_PORT:
118 case FLOWSPEC_DEST_PORT:
119 case FLOWSPEC_SRC_PORT:
120 case FLOWSPEC_ICMP_TYPE:
121 case FLOWSPEC_ICMP_CODE:
122 ret = bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY,
123 nlri_content+offset,
124 len - offset,
125 NULL, &error);
126 break;
127 case FLOWSPEC_TCP_FLAGS:
128 ret = bgp_flowspec_tcpflags_decode(
129 BGP_FLOWSPEC_VALIDATE_ONLY,
130 nlri_content+offset,
131 len - offset,
132 NULL, &error);
133 break;
134 case FLOWSPEC_PKT_LEN:
135 case FLOWSPEC_DSCP:
136 ret = bgp_flowspec_op_decode(
137 BGP_FLOWSPEC_VALIDATE_ONLY,
138 nlri_content + offset,
139 len - offset, NULL,
140 &error);
141 break;
142 case FLOWSPEC_FRAGMENT:
143 ret = bgp_flowspec_fragment_type_decode(
144 BGP_FLOWSPEC_VALIDATE_ONLY,
145 nlri_content + offset,
146 len - offset, NULL,
147 &error);
148 break;
149 default:
150 error = -1;
151 break;
152 }
153 offset += ret;
154 }
155 return false;
156 }
157
158 /*
159 * handle the flowspec address src/dst or generic address NLRI
160 * return number of bytes analysed ( >= 0).
161 */
162 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
163 uint8_t *nlri_ptr,
164 uint32_t max_len,
165 void *result, int *error)
166 {
167 char *display = (char *)result; /* for return_string */
168 struct prefix *prefix = (struct prefix *)result;
169 uint32_t offset = 0;
170 struct prefix prefix_local;
171 int psize;
172
173 *error = 0;
174 memset(&prefix_local, 0, sizeof(struct prefix));
175 /* read the prefix length */
176 prefix_local.prefixlen = nlri_ptr[offset];
177 psize = PSIZE(prefix_local.prefixlen);
178 offset++;
179 /* TODO Flowspec IPv6 Support */
180 prefix_local.family = AF_INET;
181 /* Prefix length check. */
182 if (prefix_local.prefixlen > prefix_blen(&prefix_local) * 8)
183 *error = -1;
184 /* When packet overflow occur return immediately. */
185 if (psize + offset > max_len)
186 *error = -1;
187 /* Defensive coding, double-check
188 * the psize fits in a struct prefix
189 */
190 if (psize > (ssize_t)sizeof(prefix_local.u))
191 *error = -1;
192 memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
193 offset += psize;
194 switch (type) {
195 case BGP_FLOWSPEC_RETURN_STRING:
196 prefix2str(&prefix_local, display,
197 BGP_FLOWSPEC_STRING_DISPLAY_MAX);
198 break;
199 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
200 PREFIX_COPY_IPV4(prefix, &prefix_local)
201 break;
202 case BGP_FLOWSPEC_VALIDATE_ONLY:
203 default:
204 break;
205 }
206 return offset;
207 }
208
209 /*
210 * handle the flowspec operator NLRI
211 * return number of bytes analysed
212 * if there is an error, the passed error param is used to give error:
213 * -1 if decoding error,
214 * if result is a string, its assumed length
215 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
216 */
217 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
218 uint8_t *nlri_ptr,
219 uint32_t max_len,
220 void *result, int *error)
221 {
222 int op[8];
223 int len, value, value_size;
224 int loop = 0;
225 char *ptr = (char *)result; /* for return_string */
226 uint32_t offset = 0;
227 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
228 int len_written;
229 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
230
231 *error = 0;
232 do {
233 if (loop > BGP_PBR_MATCH_VAL_MAX)
234 *error = -2;
235 hex2bin(&nlri_ptr[offset], op);
236 offset++;
237 len = 2*op[2]+op[3];
238 value_size = 1 << len;
239 value = hexstr2num(&nlri_ptr[offset], value_size);
240 /* can not be < and > at the same time */
241 if (op[5] == 1 && op[6] == 1)
242 *error = -1;
243 /* if first element, AND bit can not be set */
244 if (op[1] == 1 && loop == 0)
245 *error = -1;
246 switch (type) {
247 case BGP_FLOWSPEC_RETURN_STRING:
248 if (loop) {
249 len_written = snprintf(ptr, len_string,
250 ", ");
251 len_string -= len_written;
252 ptr += len_written;
253 }
254 if (op[5] == 1) {
255 len_written = snprintf(ptr, len_string,
256 "<");
257 len_string -= len_written;
258 ptr += len_written;
259 }
260 if (op[6] == 1) {
261 len_written = snprintf(ptr, len_string,
262 ">");
263 len_string -= len_written;
264 ptr += len_written;
265 }
266 if (op[7] == 1) {
267 len_written = snprintf(ptr, len_string,
268 "=");
269 len_string -= len_written;
270 ptr += len_written;
271 }
272 len_written = snprintf(ptr, len_string,
273 " %d ", value);
274 len_string -= len_written;
275 ptr += len_written;
276 break;
277 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
278 /* limitation: stop converting */
279 if (*error == -2)
280 break;
281 mval->value = value;
282 if (op[5] == 1)
283 mval->compare_operator |=
284 OPERATOR_COMPARE_LESS_THAN;
285 if (op[6] == 1)
286 mval->compare_operator |=
287 OPERATOR_COMPARE_GREATER_THAN;
288 if (op[7] == 1)
289 mval->compare_operator |=
290 OPERATOR_COMPARE_EQUAL_TO;
291 if (op[1] == 1)
292 mval->unary_operator = OPERATOR_UNARY_AND;
293 else
294 mval->unary_operator = OPERATOR_UNARY_OR;
295 mval++;
296 break;
297 case BGP_FLOWSPEC_VALIDATE_ONLY:
298 default:
299 /* no action */
300 break;
301 }
302 offset += value_size;
303 loop++;
304 } while (op[0] == 0 && offset < max_len - 1);
305 if (offset > max_len)
306 *error = -1;
307 /* use error parameter to count the number of entries */
308 if (*error == 0)
309 *error = loop;
310 return offset;
311 }
312
313
314 /*
315 * handle the flowspec tcpflags field
316 * return number of bytes analysed
317 * if there is an error, the passed error param is used to give error:
318 * -1 if decoding error,
319 * if result is a string, its assumed length
320 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
321 */
322 int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type,
323 uint8_t *nlri_ptr,
324 uint32_t max_len,
325 void *result, int *error)
326 {
327 int op[8];
328 int len, value_size, loop = 0, value;
329 char *ptr = (char *)result; /* for return_string */
330 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
331 uint32_t offset = 0;
332 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
333 int len_written;
334
335 *error = 0;
336 do {
337 if (loop > BGP_PBR_MATCH_VAL_MAX)
338 *error = -2;
339 hex2bin(&nlri_ptr[offset], op);
340 /* if first element, AND bit can not be set */
341 if (op[1] == 1 && loop == 0)
342 *error = -1;
343 offset++;
344 len = 2 * op[2] + op[3];
345 value_size = 1 << len;
346 value = hexstr2num(&nlri_ptr[offset], value_size);
347 switch (type) {
348 case BGP_FLOWSPEC_RETURN_STRING:
349 if (op[1] == 1 && loop != 0) {
350 len_written = snprintf(ptr, len_string,
351 ",&");
352 len_string -= len_written;
353 ptr += len_written;
354 } else if (op[1] == 0 && loop != 0) {
355 len_written = snprintf(ptr, len_string,
356 ",|");
357 len_string -= len_written;
358 ptr += len_written;
359 }
360 if (op[7] == 1) {
361 len_written = snprintf(ptr, len_string,
362 "= ");
363 len_string -= len_written;
364 ptr += len_written;
365 } else {
366 len_written = snprintf(ptr, len_string,
367 "∋ ");
368 len_string -= len_written;
369 ptr += len_written;
370 }
371 if (op[6] == 1) {
372 len_written = snprintf(ptr, len_string,
373 "! ");
374 len_string -= len_written;
375 ptr += len_written;
376 }
377 len_written = snprintf(ptr, len_string,
378 "%d", value);
379 len_string -= len_written;
380 ptr += len_written;
381 break;
382 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
383 /* limitation: stop converting */
384 if (*error == -2)
385 break;
386 mval->value = value;
387 if (op[6] == 1) {
388 /* different from */
389 mval->compare_operator |=
390 OPERATOR_COMPARE_LESS_THAN;
391 mval->compare_operator |=
392 OPERATOR_COMPARE_GREATER_THAN;
393 } else
394 mval->compare_operator |=
395 OPERATOR_COMPARE_EQUAL_TO;
396 if (op[7] == 1)
397 mval->compare_operator |=
398 OPERATOR_COMPARE_EXACT_MATCH;
399 if (op[1] == 1)
400 mval->unary_operator =
401 OPERATOR_UNARY_AND;
402 else
403 mval->unary_operator =
404 OPERATOR_UNARY_OR;
405 mval++;
406 break;
407 case BGP_FLOWSPEC_VALIDATE_ONLY:
408 default:
409 /* no action */
410 break;
411 }
412 offset += value_size;
413 loop++;
414 } while (op[0] == 0 && offset < max_len - 1);
415 if (offset > max_len)
416 *error = -1;
417 /* use error parameter to count the number of entries */
418 if (*error == 0)
419 *error = loop;
420 return offset;
421 }
422
423 /*
424 * handle the flowspec fragment type field
425 * return error (returned values are invalid) or number of bytes analysed
426 * -1 if error in decoding
427 * >= 0 : number of bytes analysed (ok).
428 */
429 int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type,
430 uint8_t *nlri_ptr,
431 uint32_t max_len,
432 void *result, int *error)
433 {
434 int op[8];
435 int len, value, value_size, loop = 0;
436 char *ptr = (char *)result; /* for return_string */
437 struct bgp_pbr_fragment_val *mval =
438 (struct bgp_pbr_fragment_val *)result;
439 uint32_t offset = 0;
440 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
441 int len_written;
442
443 *error = 0;
444 do {
445 hex2bin(&nlri_ptr[offset], op);
446 offset++;
447 len = 2 * op[2] + op[3];
448 value_size = 1 << len;
449 value = hexstr2num(&nlri_ptr[offset], value_size);
450 if (value != 1 && value != 2 && value != 4 && value != 8)
451 *error = -1;
452 offset += value_size;
453 /* TODO : as per RFC5574 : first Fragment bits are Reserved
454 * does that mean that it is not possible
455 * to handle multiple occurences ?
456 * as of today, we only grab the first TCP fragment
457 */
458 if (loop) {
459 *error = -2;
460 loop++;
461 continue;
462 }
463 switch (type) {
464 case BGP_FLOWSPEC_RETURN_STRING:
465 switch (value) {
466 case 1:
467 len_written = snprintf(ptr, len_string,
468 "dont-fragment");
469 len_string -= len_written;
470 ptr += len_written;
471 break;
472 case 2:
473 len_written = snprintf(ptr, len_string,
474 "is-fragment");
475 len_string -= len_written;
476 ptr += len_written;
477 break;
478 case 4:
479 len_written = snprintf(ptr, len_string,
480 "first-fragment");
481 len_string -= len_written;
482 ptr += len_written;
483 break;
484 case 8:
485 len_written = snprintf(ptr, len_string,
486 "last-fragment");
487 len_string -= len_written;
488 ptr += len_written;
489 break;
490 default:
491 {}
492 }
493 break;
494 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
495 mval->bitmask = (uint8_t)value;
496 break;
497 case BGP_FLOWSPEC_VALIDATE_ONLY:
498 default:
499 /* no action */
500 break;
501 }
502 loop++;
503 } while (op[0] == 0 && offset < max_len - 1);
504 if (offset > max_len)
505 *error = -1;
506 return offset;
507 }
508
509 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
510 struct bgp_pbr_entry_main *bpem)
511 {
512 int offset = 0, error = 0;
513 struct prefix *prefix;
514 struct bgp_pbr_match_val *mval;
515 uint8_t *match_num;
516 uint8_t bitmask = 0;
517 int ret = 0, type;
518
519 while (offset < len - 1 && error >= 0) {
520 type = nlri_content[offset];
521 offset++;
522 switch (type) {
523 case FLOWSPEC_DEST_PREFIX:
524 case FLOWSPEC_SRC_PREFIX:
525 bitmask = 0;
526 if (type == FLOWSPEC_DEST_PREFIX) {
527 bitmask |= PREFIX_DST_PRESENT;
528 prefix = &bpem->dst_prefix;
529 } else {
530 bitmask |= PREFIX_SRC_PRESENT;
531 prefix = &bpem->src_prefix;
532 }
533 ret = bgp_flowspec_ip_address(
534 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
535 nlri_content + offset,
536 len - offset,
537 prefix, &error);
538 if (error < 0)
539 zlog_err("%s: flowspec_ip_address error %d",
540 __func__, error);
541 else
542 bpem->match_bitmask |= bitmask;
543 offset += ret;
544 break;
545 case FLOWSPEC_IP_PROTOCOL:
546 match_num = &(bpem->match_protocol_num);
547 mval = (struct bgp_pbr_match_val *)
548 &(bpem->protocol);
549 offset += bgp_flowspec_call_non_opaque_decode(
550 nlri_content + offset,
551 len - offset,
552 mval, match_num,
553 &error);
554 break;
555 case FLOWSPEC_PORT:
556 match_num = &(bpem->match_port_num);
557 mval = (struct bgp_pbr_match_val *)
558 &(bpem->port);
559 offset += bgp_flowspec_call_non_opaque_decode(
560 nlri_content + offset,
561 len - offset,
562 mval, match_num,
563 &error);
564 break;
565 case FLOWSPEC_DEST_PORT:
566 match_num = &(bpem->match_dst_port_num);
567 mval = (struct bgp_pbr_match_val *)
568 &(bpem->dst_port);
569 offset += bgp_flowspec_call_non_opaque_decode(
570 nlri_content + offset,
571 len - offset,
572 mval, match_num,
573 &error);
574 break;
575 case FLOWSPEC_SRC_PORT:
576 match_num = &(bpem->match_src_port_num);
577 mval = (struct bgp_pbr_match_val *)
578 &(bpem->src_port);
579 offset += bgp_flowspec_call_non_opaque_decode(
580 nlri_content + offset,
581 len - offset,
582 mval, match_num,
583 &error);
584 break;
585 case FLOWSPEC_ICMP_TYPE:
586 match_num = &(bpem->match_icmp_type_num);
587 mval = (struct bgp_pbr_match_val *)
588 &(bpem->icmp_type);
589 offset += bgp_flowspec_call_non_opaque_decode(
590 nlri_content + offset,
591 len - offset,
592 mval, match_num,
593 &error);
594 break;
595 case FLOWSPEC_ICMP_CODE:
596 match_num = &(bpem->match_icmp_code_num);
597 mval = (struct bgp_pbr_match_val *)
598 &(bpem->icmp_code);
599 offset += bgp_flowspec_call_non_opaque_decode(
600 nlri_content + offset,
601 len - offset,
602 mval, match_num,
603 &error);
604 break;
605 case FLOWSPEC_PKT_LEN:
606 match_num =
607 &(bpem->match_packet_length_num);
608 mval = (struct bgp_pbr_match_val *)
609 &(bpem->packet_length);
610 offset += bgp_flowspec_call_non_opaque_decode(
611 nlri_content + offset,
612 len - offset,
613 mval, match_num,
614 &error);
615 break;
616 case FLOWSPEC_DSCP:
617 match_num = &(bpem->match_dscp_num);
618 mval = (struct bgp_pbr_match_val *)
619 &(bpem->dscp);
620 offset += bgp_flowspec_call_non_opaque_decode(
621 nlri_content + offset,
622 len - offset,
623 mval, match_num,
624 &error);
625 break;
626 case FLOWSPEC_TCP_FLAGS:
627 ret = bgp_flowspec_tcpflags_decode(
628 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
629 nlri_content + offset,
630 len - offset,
631 &bpem->tcpflags, &error);
632 if (error < 0)
633 zlog_err("%s: flowspec_tcpflags_decode error %d",
634 __func__, error);
635 else
636 bpem->match_tcpflags_num = error;
637 /* contains the number of slots used */
638 offset += ret;
639 break;
640 case FLOWSPEC_FRAGMENT:
641 ret = bgp_flowspec_fragment_type_decode(
642 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
643 nlri_content + offset,
644 len - offset, &bpem->fragment,
645 &error);
646 if (error < 0)
647 zlog_err("%s: flowspec_fragment_type_decode error %d",
648 __func__, error);
649 else
650 bpem->match_bitmask |= FRAGMENT_PRESENT;
651 offset += ret;
652 break;
653 default:
654 zlog_err("%s: unknown type %d\n", __func__, type);
655 }
656 }
657 return error;
658 }
659
660
661 struct bgp_node *bgp_flowspec_get_match_per_ip(afi_t afi,
662 struct bgp_table *rib,
663 struct prefix *match,
664 int prefix_check)
665 {
666 struct bgp_node *rn;
667 struct prefix *prefix;
668
669 for (rn = bgp_table_top(rib); rn; rn = bgp_route_next(rn)) {
670 prefix = &rn->p;
671
672 if (prefix->family != AF_FLOWSPEC)
673 continue;
674
675 if (bgp_flowspec_contains_prefix(prefix, match, prefix_check))
676 return rn;
677 }
678 return NULL;
679 }