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
25 #include "bgp_table.h"
26 #include "bgp_flowspec_util.h"
27 #include "bgp_flowspec_private.h"
29 static void hex2bin(uint8_t *hex
, int *bin
)
34 while (remainder
>= 1 && i
< 8) {
35 bin
[7-i
] = remainder
% 2;
36 remainder
= remainder
/ 2;
43 static int hexstr2num(uint8_t *hexstr
, int len
)
48 for (i
= 0; i
< len
; i
++)
49 num
= hexstr
[i
] + 16*16*num
;
55 * handle the flowspec address src/dst or generic address NLRI
56 * return number of bytes analysed ( >= 0).
58 int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type
,
61 void *result
, int *error
)
63 char *display
= (char *)result
; /* for return_string */
64 struct prefix
*prefix
= (struct prefix
*)result
;
66 struct prefix prefix_local
;
70 memset(&prefix_local
, 0, sizeof(struct prefix
));
71 /* read the prefix length */
72 prefix_local
.prefixlen
= nlri_ptr
[offset
];
73 psize
= PSIZE(prefix_local
.prefixlen
);
75 /* TODO Flowspec IPv6 Support */
76 prefix_local
.family
= AF_INET
;
77 /* Prefix length check. */
78 if (prefix_local
.prefixlen
> prefix_blen(&prefix_local
) * 8)
80 /* When packet overflow occur return immediately. */
81 if (psize
+ offset
> max_len
)
83 /* Defensive coding, double-check
84 * the psize fits in a struct prefix
86 if (psize
> (ssize_t
)sizeof(prefix_local
.u
))
88 memcpy(&prefix_local
.u
.prefix
, &nlri_ptr
[offset
], psize
);
91 case BGP_FLOWSPEC_RETURN_STRING
:
92 prefix2str(&prefix_local
, display
,
93 BGP_FLOWSPEC_STRING_DISPLAY_MAX
);
95 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
96 PREFIX_COPY_IPV4(prefix
, &prefix_local
)
98 case BGP_FLOWSPEC_VALIDATE_ONLY
:
106 * handle the flowspec operator NLRI
107 * return number of bytes analysed
108 * if there is an error, the passed error param is used to give error:
109 * -1 if decoding error,
110 * if result is a string, its assumed length
111 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
113 int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type
,
116 void *result
, int *error
)
119 int len
, value
, value_size
;
121 char *ptr
= (char *)result
; /* for return_string */
123 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
128 hex2bin(&nlri_ptr
[offset
], op
);
131 value_size
= 1 << len
;
132 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
133 /* can not be < and > at the same time */
134 if (op
[5] == 1 && op
[6] == 1)
136 /* if first element, AND bit can not be set */
137 if (op
[1] == 1 && loop
== 0)
140 case BGP_FLOWSPEC_RETURN_STRING
:
142 len_written
= snprintf(ptr
, len_string
,
144 len_string
-= len_written
;
148 len_written
= snprintf(ptr
, len_string
,
150 len_string
-= len_written
;
154 len_written
= snprintf(ptr
, len_string
,
156 len_string
-= len_written
;
160 len_written
= snprintf(ptr
, len_string
,
162 len_string
-= len_written
;
165 len_written
= snprintf(ptr
, len_string
,
167 len_string
-= len_written
;
170 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
171 /* TODO : FS OPAQUE */
173 case BGP_FLOWSPEC_VALIDATE_ONLY
:
178 offset
+= value_size
;
180 } while (op
[0] == 0 && offset
< max_len
- 1);
181 if (offset
> max_len
)
183 /* use error parameter to count the number of entries */
191 * handle the flowspec tcpflags field
192 * return number of bytes analysed
193 * if there is an error, the passed error param is used to give error:
194 * -1 if decoding error,
195 * if result is a string, its assumed length
196 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
198 int bgp_flowspec_tcpflags_decode(enum bgp_flowspec_util_nlri_t type
,
201 void *result
, int *error
)
204 int len
, value_size
, loop
= 0, value
;
205 char *ptr
= (char *)result
; /* for return_string */
207 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
212 hex2bin(&nlri_ptr
[offset
], op
);
213 /* if first element, AND bit can not be set */
214 if (op
[1] == 1 && loop
== 0)
217 len
= 2 * op
[2] + op
[3];
218 value_size
= 1 << len
;
219 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
221 case BGP_FLOWSPEC_RETURN_STRING
:
222 if (op
[1] == 1 && loop
!= 0) {
223 len_written
= snprintf(ptr
, len_string
,
225 len_string
-= len_written
;
227 } else if (op
[1] == 0 && loop
!= 0) {
228 len_written
= snprintf(ptr
, len_string
,
230 len_string
-= len_written
;
233 len_written
= snprintf(ptr
, len_string
,
235 len_string
-= len_written
;
238 ptr
+= snprintf(ptr
, len_string
,
240 len_string
-= len_written
;
244 ptr
+= snprintf(ptr
, len_string
,
246 len_string
-= len_written
;
249 ptr
+= snprintf(ptr
, len_string
,
251 len_string
-= len_written
;
254 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
255 /* TODO : FS OPAQUE */
257 case BGP_FLOWSPEC_VALIDATE_ONLY
:
262 offset
+= value_size
;
264 } while (op
[0] == 0 && offset
< max_len
- 1);
265 if (offset
> max_len
)
267 /* use error parameter to count the number of entries */
274 * handle the flowspec fragment type field
275 * return error (returned values are invalid) or number of bytes analysed
276 * -1 if error in decoding
277 * >= 0 : number of bytes analysed (ok).
279 int bgp_flowspec_fragment_type_decode(enum bgp_flowspec_util_nlri_t type
,
282 void *result
, int *error
)
285 int len
, value
, value_size
, loop
= 0;
286 char *ptr
= (char *)result
; /* for return_string */
288 int len_string
= BGP_FLOWSPEC_STRING_DISPLAY_MAX
;
293 hex2bin(&nlri_ptr
[offset
], op
);
295 len
= 2 * op
[2] + op
[3];
296 value_size
= 1 << len
;
297 value
= hexstr2num(&nlri_ptr
[offset
], value_size
);
298 if (value
!= 1 && value
!= 2 && value
!= 4 && value
!= 8)
300 offset
+= value_size
;
301 /* TODO : as per RFC5574 : first Fragment bits are Reserved
302 * does that mean that it is not possible
303 * to handle multiple occurences ?
304 * as of today, we only grab the first TCP fragment
312 case BGP_FLOWSPEC_RETURN_STRING
:
315 len_written
= snprintf(ptr
, len_string
,
317 len_string
-= len_written
;
321 len_written
= snprintf(ptr
, len_string
,
323 len_string
-= len_written
;
327 len_written
= snprintf(ptr
, len_string
,
329 len_string
-= len_written
;
333 len_written
= snprintf(ptr
, len_string
,
335 len_string
-= len_written
;
342 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
:
343 /* TODO : FS OPAQUE */
345 case BGP_FLOWSPEC_VALIDATE_ONLY
:
351 } while (op
[0] == 0 && offset
< max_len
- 1);
352 if (offset
> max_len
)
358 static bool bgp_flowspec_contains_prefix(struct prefix
*pfs
,
359 struct prefix
*input
,
364 int ret
= 0, error
= 0;
365 uint8_t *nlri_content
= (uint8_t *)pfs
->u
.prefix_flowspec
.ptr
;
366 size_t len
= pfs
->u
.prefix_flowspec
.prefixlen
;
367 struct prefix compare
;
370 while (offset
< len
-1 && error
>= 0) {
371 type
= nlri_content
[offset
];
374 case FLOWSPEC_DEST_PREFIX
:
375 case FLOWSPEC_SRC_PREFIX
:
376 memset(&compare
, 0, sizeof(struct prefix
));
377 ret
= bgp_flowspec_ip_address(
378 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE
,
385 compare
.prefixlen
!= input
->prefixlen
)
387 if (compare
.family
!= input
->family
)
389 if ((input
->family
== AF_INET
) &&
390 IPV4_ADDR_SAME(&input
->u
.prefix4
,
393 if ((input
->family
== AF_INET6
) &&
394 IPV6_ADDR_SAME(&input
->u
.prefix6
.s6_addr
,
395 &compare
.u
.prefix6
.s6_addr
))
398 case FLOWSPEC_IP_PROTOCOL
:
400 case FLOWSPEC_DEST_PORT
:
401 case FLOWSPEC_SRC_PORT
:
402 case FLOWSPEC_ICMP_TYPE
:
403 case FLOWSPEC_ICMP_CODE
:
404 ret
= bgp_flowspec_op_decode(BGP_FLOWSPEC_VALIDATE_ONLY
,
409 case FLOWSPEC_TCP_FLAGS
:
410 ret
= bgp_flowspec_tcpflags_decode(
411 BGP_FLOWSPEC_VALIDATE_ONLY
,
416 case FLOWSPEC_PKT_LEN
:
418 ret
= bgp_flowspec_op_decode(
419 BGP_FLOWSPEC_VALIDATE_ONLY
,
420 nlri_content
+ offset
,
424 case FLOWSPEC_FRAGMENT
:
425 ret
= bgp_flowspec_fragment_type_decode(
426 BGP_FLOWSPEC_VALIDATE_ONLY
,
427 nlri_content
+ offset
,
440 struct bgp_node
*bgp_flowspec_get_match_per_ip(afi_t afi
,
441 struct bgp_table
*rib
,
442 struct prefix
*match
,
446 struct prefix
*prefix
;
448 for (rn
= bgp_table_top(rib
); rn
; rn
= bgp_route_next(rn
)) {
451 if (prefix
->family
!= AF_FLOWSPEC
)
454 if (bgp_flowspec_contains_prefix(prefix
, match
, prefix_check
))