1 /* BGP FlowSpec Utilities
3 * Copyright (C) 2017 ChinaTelecom SDN Group
4 * Copyright (C) 2018 6WIND
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
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.
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
24 #include "lib_errors.h"
26 #include "bgp_route.h"
27 #include "bgp_table.h"
28 #include "bgp_flowspec_util.h"
29 #include "bgp_flowspec_private.h"
31 #include "bgp_errors.h"
33 static void hex2bin(uint8_t *hex
, int *bin
)
38 while (remainder
>= 1 && i
< 8) {
39 bin
[7-i
] = remainder
% 2;
40 remainder
= remainder
/ 2;
47 static int hexstr2num(uint8_t *hexstr
, int len
)
52 for (i
= 0; i
< len
; i
++)
53 num
= hexstr
[i
] + 16*16*num
;
57 /* call bgp_flowspec_op_decode
60 static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content
, int len
,
61 struct bgp_pbr_match_val
*mval
,
62 uint8_t *match_num
, int *error
)
66 ret
= bgp_flowspec_op_decode(
67 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
72 flog_err(EC_BGP_FLOWSPEC_PACKET
,
73 "%s: flowspec_op_decode error %d", __func__
, *error
);
79 bool bgp_flowspec_contains_prefix(struct prefix
*pfs
,
85 int ret
= 0, error
= 0;
86 uint8_t *nlri_content
= (uint8_t *)pfs
->u
.prefix_flowspec
.ptr
;
87 size_t len
= pfs
->u
.prefix_flowspec
.prefixlen
;
88 struct prefix compare
;
91 while (offset
< len
-1 && error
>= 0) {
92 type
= nlri_content
[offset
];
95 case FLOWSPEC_DEST_PREFIX
:
96 case FLOWSPEC_SRC_PREFIX
:
97 memset(&compare
, 0, sizeof(struct prefix
));
98 ret
= bgp_flowspec_ip_address(
99 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
106 compare
.prefixlen
!= input
->prefixlen
)
108 if (compare
.family
!= input
->family
)
110 if ((input
->family
== AF_INET
) &&
111 IPV4_ADDR_SAME(&input
->u
.prefix4
,
114 if ((input
->family
== AF_INET6
) &&
115 IPV6_ADDR_SAME(&input
->u
.prefix6
.s6_addr
,
116 &compare
.u
.prefix6
.s6_addr
))
119 case FLOWSPEC_IP_PROTOCOL
:
121 case FLOWSPEC_DEST_PORT
:
122 case FLOWSPEC_SRC_PORT
:
123 case FLOWSPEC_ICMP_TYPE
:
124 case FLOWSPEC_ICMP_CODE
:
125 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
130 case FLOWSPEC_FRAGMENT
:
131 case FLOWSPEC_TCP_FLAGS
:
132 ret
= bgp_flowspec_bitmask_decode(
133 BGP_FLOWSPEC_VALIDATE_ONLY
,
138 case FLOWSPEC_PKT_LEN
:
140 ret
= bgp_flowspec_op_decode(
141 BGP_FLOWSPEC_VALIDATE_ONLY
,
142 nlri_content
+ offset
,
156 * handle the flowspec address src/dst or generic address NLRI
157 * return number of bytes analysed ( >= 0).
159 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type
,
162 void *result
, int *error
)
164 char *display
= (char *)result
; /* for return_string */
165 struct prefix
*prefix
= (struct prefix
*)result
;
167 struct prefix prefix_local
;
171 memset(&prefix_local
, 0, sizeof(struct prefix
));
172 /* read the prefix length */
173 prefix_local
.prefixlen
= nlri_ptr
[offset
];
174 psize
= PSIZE(prefix_local
.prefixlen
);
176 /* TODO Flowspec IPv6 Support */
177 prefix_local
.family
= AF_INET
;
178 /* Prefix length check. */
179 if (prefix_local
.prefixlen
> prefix_blen(&prefix_local
) * 8)
181 /* When packet overflow occur return immediately. */
182 if (psize
+ offset
> max_len
)
184 /* Defensive coding, double-check
185 * the psize fits in a struct prefix
187 if (psize
> (ssize_t
)sizeof(prefix_local
.u
))
189 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
192 case BGP_FLOWSPEC_RETURN_STRING
:
193 prefix2str(&prefix_local
, display
,
194 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
196 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
197 PREFIX_COPY_IPV4(prefix
, &prefix_local
)
199 case BGP_FLOWSPEC_VALIDATE_ONLY
:
207 * handle the flowspec operator NLRI
208 * return number of bytes analysed
209 * if there is an error, the passed error param is used to give error:
210 * -1 if decoding error,
211 * if result is a string, its assumed length
212 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
214 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
217 void *result
, int *error
)
220 int len
, value
, value_size
;
222 char *ptr
= (char *)result
; /* for return_string */
224 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
226 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
230 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
232 hex2bin(&nlri_ptr
[offset
], op
);
235 value_size
= 1 << len
;
236 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
237 /* can not be < and > at the same time */
238 if (op
[5] == 1 && op
[6] == 1)
240 /* if first element, AND bit can not be set */
241 if (op
[1] == 1 && loop
== 0)
244 case BGP_FLOWSPEC_RETURN_STRING
:
246 len_written
= snprintf(ptr
, len_string
,
248 len_string
-= len_written
;
252 len_written
= snprintf(ptr
, len_string
,
254 len_string
-= len_written
;
258 len_written
= snprintf(ptr
, len_string
,
260 len_string
-= len_written
;
264 len_written
= snprintf(ptr
, len_string
,
266 len_string
-= len_written
;
269 len_written
= snprintf(ptr
, len_string
,
271 len_string
-= len_written
;
274 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
275 /* limitation: stop converting */
280 mval
->compare_operator
|=
281 OPERATOR_COMPARE_LESS_THAN
;
283 mval
->compare_operator
|=
284 OPERATOR_COMPARE_GREATER_THAN
;
286 mval
->compare_operator
|=
287 OPERATOR_COMPARE_EQUAL_TO
;
289 mval
->unary_operator
= OPERATOR_UNARY_AND
;
291 mval
->unary_operator
= OPERATOR_UNARY_OR
;
294 case BGP_FLOWSPEC_VALIDATE_ONLY
:
299 offset
+= value_size
;
301 } while (op
[0] == 0 && offset
< max_len
- 1);
302 if (offset
> max_len
)
304 /* use error parameter to count the number of entries */
312 * handle the flowspec tcpflags or fragment field
313 * return number of bytes analysed
314 * if there is an error, the passed error param is used to give error:
315 * -1 if decoding error,
316 * if result is a string, its assumed length
317 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
319 int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type
,
322 void *result
, int *error
)
325 int len
, value_size
, loop
= 0, value
;
326 char *ptr
= (char *)result
; /* for return_string */
327 struct bgp_pbr_match_val
*mval
= (struct bgp_pbr_match_val
*)result
;
329 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
334 if (loop
> BGP_PBR_MATCH_VAL_MAX
)
336 hex2bin(&nlri_ptr
[offset
], op
);
337 /* if first element, AND bit can not be set */
338 if (op
[1] == 1 && loop
== 0)
341 len
= 2 * op
[2] + op
[3];
342 value_size
= 1 << len
;
343 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
345 case BGP_FLOWSPEC_RETURN_STRING
:
346 if (op
[1] == 1 && loop
!= 0) {
347 len_written
= snprintf(ptr
, len_string
,
349 len_string
-= len_written
;
351 } else if (op
[1] == 0 && loop
!= 0) {
352 len_written
= snprintf(ptr
, len_string
,
354 len_string
-= len_written
;
358 len_written
= snprintf(ptr
, len_string
,
360 len_string
-= len_written
;
363 len_written
= snprintf(ptr
, len_string
,
365 len_string
-= len_written
;
369 len_written
= snprintf(ptr
, len_string
,
371 len_string
-= len_written
;
374 len_written
= snprintf(ptr
, len_string
,
376 len_string
-= len_written
;
379 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
380 /* limitation: stop converting */
386 mval
->compare_operator
|=
387 OPERATOR_COMPARE_LESS_THAN
;
388 mval
->compare_operator
|=
389 OPERATOR_COMPARE_GREATER_THAN
;
391 mval
->compare_operator
|=
392 OPERATOR_COMPARE_EQUAL_TO
;
394 mval
->compare_operator
|=
395 OPERATOR_COMPARE_EXACT_MATCH
;
397 mval
->unary_operator
=
400 mval
->unary_operator
=
404 case BGP_FLOWSPEC_VALIDATE_ONLY
:
409 offset
+= value_size
;
411 } while (op
[0] == 0 && offset
< max_len
- 1);
412 if (offset
> max_len
)
414 /* use error parameter to count the number of entries */
420 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content
, int len
,
421 struct bgp_pbr_entry_main
*bpem
)
423 int offset
= 0, error
= 0;
424 struct prefix
*prefix
;
425 struct bgp_pbr_match_val
*mval
;
430 while (offset
< len
- 1 && error
>= 0) {
431 type
= nlri_content
[offset
];
434 case FLOWSPEC_DEST_PREFIX
:
435 case FLOWSPEC_SRC_PREFIX
:
437 if (type
== FLOWSPEC_DEST_PREFIX
) {
438 bitmask
|= PREFIX_DST_PRESENT
;
439 prefix
= &bpem
->dst_prefix
;
441 bitmask
|= PREFIX_SRC_PRESENT
;
442 prefix
= &bpem
->src_prefix
;
444 ret
= bgp_flowspec_ip_address(
445 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
446 nlri_content
+ offset
,
450 flog_err(EC_BGP_FLOWSPEC_PACKET
,
451 "%s: flowspec_ip_address error %d",
454 /* if src or dst address is 0.0.0.0,
457 if (prefix
->family
== AF_INET
458 && prefix
->u
.prefix4
.s_addr
== 0)
459 bpem
->match_bitmask_iprule
|= bitmask
;
461 bpem
->match_bitmask
|= bitmask
;
465 case FLOWSPEC_IP_PROTOCOL
:
466 match_num
= &(bpem
->match_protocol_num
);
467 mval
= (struct bgp_pbr_match_val
*)
469 offset
+= bgp_flowspec_call_non_opaque_decode(
470 nlri_content
+ offset
,
476 match_num
= &(bpem
->match_port_num
);
477 mval
= (struct bgp_pbr_match_val
*)
479 offset
+= bgp_flowspec_call_non_opaque_decode(
480 nlri_content
+ offset
,
485 case FLOWSPEC_DEST_PORT
:
486 match_num
= &(bpem
->match_dst_port_num
);
487 mval
= (struct bgp_pbr_match_val
*)
489 offset
+= bgp_flowspec_call_non_opaque_decode(
490 nlri_content
+ offset
,
495 case FLOWSPEC_SRC_PORT
:
496 match_num
= &(bpem
->match_src_port_num
);
497 mval
= (struct bgp_pbr_match_val
*)
499 offset
+= bgp_flowspec_call_non_opaque_decode(
500 nlri_content
+ offset
,
505 case FLOWSPEC_ICMP_TYPE
:
506 match_num
= &(bpem
->match_icmp_type_num
);
507 mval
= (struct bgp_pbr_match_val
*)
509 offset
+= bgp_flowspec_call_non_opaque_decode(
510 nlri_content
+ offset
,
515 case FLOWSPEC_ICMP_CODE
:
516 match_num
= &(bpem
->match_icmp_code_num
);
517 mval
= (struct bgp_pbr_match_val
*)
519 offset
+= bgp_flowspec_call_non_opaque_decode(
520 nlri_content
+ offset
,
525 case FLOWSPEC_PKT_LEN
:
527 &(bpem
->match_packet_length_num
);
528 mval
= (struct bgp_pbr_match_val
*)
529 &(bpem
->packet_length
);
530 offset
+= bgp_flowspec_call_non_opaque_decode(
531 nlri_content
+ offset
,
537 match_num
= &(bpem
->match_dscp_num
);
538 mval
= (struct bgp_pbr_match_val
*)
540 offset
+= bgp_flowspec_call_non_opaque_decode(
541 nlri_content
+ offset
,
546 case FLOWSPEC_TCP_FLAGS
:
547 ret
= bgp_flowspec_bitmask_decode(
548 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
549 nlri_content
+ offset
,
551 &bpem
->tcpflags
, &error
);
554 EC_BGP_FLOWSPEC_PACKET
,
555 "%s: flowspec_tcpflags_decode error %d",
558 bpem
->match_tcpflags_num
= error
;
559 /* contains the number of slots used */
562 case FLOWSPEC_FRAGMENT
:
563 ret
= bgp_flowspec_bitmask_decode(
564 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
565 nlri_content
+ offset
,
566 len
- offset
, &bpem
->fragment
,
570 EC_BGP_FLOWSPEC_PACKET
,
571 "%s: flowspec_fragment_type_decode error %d",
574 bpem
->match_fragment_num
= error
;
578 flog_err(EC_LIB_DEVELOPMENT
, "%s: unknown type %d\n",
582 if (bpem
->match_packet_length_num
|| bpem
->match_fragment_num
||
583 bpem
->match_tcpflags_num
|| bpem
->match_dscp_num
||
584 bpem
->match_packet_length_num
|| bpem
->match_icmp_code_num
||
585 bpem
->match_icmp_type_num
|| bpem
->match_port_num
||
586 bpem
->match_src_port_num
|| bpem
->match_dst_port_num
||
587 bpem
->match_protocol_num
|| bpem
->match_bitmask
)
588 bpem
->type
= BGP_PBR_IPSET
;
589 else if ((bpem
->match_bitmask_iprule
& PREFIX_SRC_PRESENT
) ||
590 (bpem
->match_bitmask_iprule
& PREFIX_DST_PRESENT
))
591 /* the extracted policy rule may not need an
592 * iptables/ipset filtering. check this may not be
593 * a standard ip rule : permit any to any ( eg)
595 bpem
->type
= BGP_PBR_IPRULE
;
597 bpem
->type
= BGP_PBR_UNDEFINED
;
601 /* return 1 if FS entry invalid or no NH IP */
602 int bgp_flowspec_get_first_nh(struct bgp
*bgp
, struct bgp_path_info
*pi
,
605 struct bgp_pbr_entry_main api
;
607 struct bgp_node
*rn
= pi
->net
;
608 struct bgp_pbr_entry_action
*api_action
;
610 memset(&api
, 0, sizeof(struct bgp_pbr_entry_main
));
611 if (bgp_pbr_build_and_validate_entry(&rn
->p
, pi
, &api
) < 0)
613 for (i
= 0; i
< api
.action_num
; i
++) {
614 api_action
= &api
.actions
[i
];
615 if (api_action
->action
!= ACTION_REDIRECT_IP
)
618 p
->prefixlen
= IPV4_MAX_BITLEN
;
619 p
->u
.prefix4
= api_action
->u
.zr
.redirect_ip_v4
;