]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_flowspec_util.c
Merge pull request #2848 from donaldsharp/more_init
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
CommitLineData
034cdee9
PG
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"
02705213 24#include "lib_errors.h"
98a9dbc7
PG
25
26#include "bgp_table.h"
034cdee9 27#include "bgp_flowspec_util.h"
98a9dbc7 28#include "bgp_flowspec_private.h"
47555ee9 29#include "bgp_pbr.h"
4f3be667 30#include "bgp_errors.h"
034cdee9
PG
31
32static void hex2bin(uint8_t *hex, int *bin)
33{
34 int remainder = *hex;
35 int i = 0;
36
37 while (remainder >= 1 && i < 8) {
38 bin[7-i] = remainder % 2;
39 remainder = remainder / 2;
40 i++;
41 }
42 for (; i < 8; i++)
43 bin[7-i] = 0;
44}
45
46static int hexstr2num(uint8_t *hexstr, int len)
47{
48 int i = 0;
49 int num = 0;
50
51 for (i = 0; i < len; i++)
52 num = hexstr[i] + 16*16*num;
53 return num;
54}
55
47555ee9
PG
56/* call bgp_flowspec_op_decode
57 * returns offset
58 */
59static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len,
60 struct bgp_pbr_match_val *mval,
61 uint8_t *match_num, int *error)
62{
63 int ret;
64
65 ret = bgp_flowspec_op_decode(
66 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
67 nlri_content,
68 len,
69 mval, error);
70 if (*error < 0)
af4c2728 71 flog_err(BGP_ERR_FLOWSPEC_PACKET,
4f3be667
DS
72 "%s: flowspec_op_decode error %d",
73 __func__, *error);
47555ee9
PG
74 else
75 *match_num = *error;
76 return ret;
77}
78
63a0b7a9
PG
79bool bgp_flowspec_contains_prefix(struct prefix *pfs,
80 struct prefix *input,
81 int prefix_check)
47555ee9
PG
82{
83 uint32_t offset = 0;
84 int type;
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;
89
90 error = 0;
91 while (offset < len-1 && error >= 0) {
92 type = nlri_content[offset];
93 offset++;
94 switch (type) {
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,
100 nlri_content+offset,
101 len - offset,
102 &compare, &error);
103 if (ret <= 0)
104 break;
105 if (prefix_check &&
106 compare.prefixlen != input->prefixlen)
107 break;
108 if (compare.family != input->family)
109 break;
110 if ((input->family == AF_INET) &&
111 IPV4_ADDR_SAME(&input->u.prefix4,
112 &compare.u.prefix4))
113 return true;
114 if ((input->family == AF_INET6) &&
115 IPV6_ADDR_SAME(&input->u.prefix6.s6_addr,
116 &compare.u.prefix6.s6_addr))
117 return true;
118 break;
119 case FLOWSPEC_IP_PROTOCOL:
120 case FLOWSPEC_PORT:
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,
126 nlri_content+offset,
127 len - offset,
128 NULL, &error);
129 break;
588ec356 130 case FLOWSPEC_FRAGMENT:
47555ee9 131 case FLOWSPEC_TCP_FLAGS:
588ec356 132 ret = bgp_flowspec_bitmask_decode(
47555ee9
PG
133 BGP_FLOWSPEC_VALIDATE_ONLY,
134 nlri_content+offset,
135 len - offset,
136 NULL, &error);
137 break;
138 case FLOWSPEC_PKT_LEN:
139 case FLOWSPEC_DSCP:
140 ret = bgp_flowspec_op_decode(
141 BGP_FLOWSPEC_VALIDATE_ONLY,
142 nlri_content + offset,
143 len - offset, NULL,
144 &error);
145 break;
47555ee9
PG
146 default:
147 error = -1;
148 break;
149 }
150 offset += ret;
151 }
152 return false;
153}
034cdee9
PG
154
155/*
156 * handle the flowspec address src/dst or generic address NLRI
157 * return number of bytes analysed ( >= 0).
158 */
159int bgp_flowspec_ip_address(enum bgp_flowspec_util_nlri_t type,
160 uint8_t *nlri_ptr,
161 uint32_t max_len,
162 void *result, int *error)
163{
164 char *display = (char *)result; /* for return_string */
165 struct prefix *prefix = (struct prefix *)result;
166 uint32_t offset = 0;
167 struct prefix prefix_local;
168 int psize;
169
170 *error = 0;
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);
175 offset++;
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)
180 *error = -1;
181 /* When packet overflow occur return immediately. */
182 if (psize + offset > max_len)
183 *error = -1;
184 /* Defensive coding, double-check
185 * the psize fits in a struct prefix
186 */
187 if (psize > (ssize_t)sizeof(prefix_local.u))
188 *error = -1;
189 memcpy(&prefix_local.u.prefix, &nlri_ptr[offset], psize);
190 offset += psize;
191 switch (type) {
192 case BGP_FLOWSPEC_RETURN_STRING:
193 prefix2str(&prefix_local, display,
194 BGP_FLOWSPEC_STRING_DISPLAY_MAX);
195 break;
196 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
197 PREFIX_COPY_IPV4(prefix, &prefix_local)
198 break;
199 case BGP_FLOWSPEC_VALIDATE_ONLY:
200 default:
201 break;
202 }
203 return offset;
204}
205
206/*
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,
362a06e3
PG
211 * if result is a string, its assumed length
212 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
034cdee9
PG
213 */
214int bgp_flowspec_op_decode(enum bgp_flowspec_util_nlri_t type,
215 uint8_t *nlri_ptr,
216 uint32_t max_len,
217 void *result, int *error)
218{
219 int op[8];
220 int len, value, value_size;
221 int loop = 0;
222 char *ptr = (char *)result; /* for return_string */
223 uint32_t offset = 0;
362a06e3
PG
224 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
225 int len_written;
47555ee9 226 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
034cdee9
PG
227
228 *error = 0;
229 do {
47555ee9
PG
230 if (loop > BGP_PBR_MATCH_VAL_MAX)
231 *error = -2;
034cdee9
PG
232 hex2bin(&nlri_ptr[offset], op);
233 offset++;
234 len = 2*op[2]+op[3];
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)
239 *error = -1;
240 /* if first element, AND bit can not be set */
241 if (op[1] == 1 && loop == 0)
242 *error = -1;
243 switch (type) {
244 case BGP_FLOWSPEC_RETURN_STRING:
362a06e3
PG
245 if (loop) {
246 len_written = snprintf(ptr, len_string,
247 ", ");
248 len_string -= len_written;
249 ptr += len_written;
250 }
251 if (op[5] == 1) {
252 len_written = snprintf(ptr, len_string,
253 "<");
254 len_string -= len_written;
255 ptr += len_written;
256 }
257 if (op[6] == 1) {
258 len_written = snprintf(ptr, len_string,
259 ">");
260 len_string -= len_written;
261 ptr += len_written;
262 }
263 if (op[7] == 1) {
264 len_written = snprintf(ptr, len_string,
265 "=");
266 len_string -= len_written;
267 ptr += len_written;
268 }
269 len_written = snprintf(ptr, len_string,
270 " %d ", value);
271 len_string -= len_written;
272 ptr += len_written;
034cdee9
PG
273 break;
274 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
47555ee9
PG
275 /* limitation: stop converting */
276 if (*error == -2)
277 break;
278 mval->value = value;
279 if (op[5] == 1)
280 mval->compare_operator |=
281 OPERATOR_COMPARE_LESS_THAN;
282 if (op[6] == 1)
283 mval->compare_operator |=
284 OPERATOR_COMPARE_GREATER_THAN;
285 if (op[7] == 1)
286 mval->compare_operator |=
287 OPERATOR_COMPARE_EQUAL_TO;
288 if (op[1] == 1)
289 mval->unary_operator = OPERATOR_UNARY_AND;
290 else
291 mval->unary_operator = OPERATOR_UNARY_OR;
292 mval++;
034cdee9
PG
293 break;
294 case BGP_FLOWSPEC_VALIDATE_ONLY:
295 default:
296 /* no action */
297 break;
298 }
299 offset += value_size;
300 loop++;
301 } while (op[0] == 0 && offset < max_len - 1);
302 if (offset > max_len)
303 *error = -1;
304 /* use error parameter to count the number of entries */
305 if (*error == 0)
306 *error = loop;
307 return offset;
308}
309
310
311/*
588ec356 312 * handle the flowspec tcpflags or fragment field
034cdee9
PG
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,
362a06e3
PG
316 * if result is a string, its assumed length
317 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
034cdee9 318 */
588ec356 319int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
034cdee9
PG
320 uint8_t *nlri_ptr,
321 uint32_t max_len,
322 void *result, int *error)
323{
324 int op[8];
325 int len, value_size, loop = 0, value;
326 char *ptr = (char *)result; /* for return_string */
47555ee9 327 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
034cdee9 328 uint32_t offset = 0;
362a06e3
PG
329 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
330 int len_written;
034cdee9
PG
331
332 *error = 0;
333 do {
47555ee9
PG
334 if (loop > BGP_PBR_MATCH_VAL_MAX)
335 *error = -2;
034cdee9
PG
336 hex2bin(&nlri_ptr[offset], op);
337 /* if first element, AND bit can not be set */
338 if (op[1] == 1 && loop == 0)
339 *error = -1;
340 offset++;
341 len = 2 * op[2] + op[3];
342 value_size = 1 << len;
343 value = hexstr2num(&nlri_ptr[offset], value_size);
344 switch (type) {
345 case BGP_FLOWSPEC_RETURN_STRING:
362a06e3
PG
346 if (op[1] == 1 && loop != 0) {
347 len_written = snprintf(ptr, len_string,
01ffd28b 348 ",&");
362a06e3
PG
349 len_string -= len_written;
350 ptr += len_written;
351 } else if (op[1] == 0 && loop != 0) {
352 len_written = snprintf(ptr, len_string,
01ffd28b 353 ",|");
362a06e3
PG
354 len_string -= len_written;
355 ptr += len_written;
356 }
01ffd28b
PG
357 if (op[7] == 1) {
358 len_written = snprintf(ptr, len_string,
359 "= ");
360 len_string -= len_written;
361 ptr += len_written;
362 } else {
363 len_written = snprintf(ptr, len_string,
364 "∋ ");
362a06e3
PG
365 len_string -= len_written;
366 ptr += len_written;
367 }
01ffd28b
PG
368 if (op[6] == 1) {
369 len_written = snprintf(ptr, len_string,
370 "! ");
362a06e3
PG
371 len_string -= len_written;
372 ptr += len_written;
373 }
01ffd28b 374 len_written = snprintf(ptr, len_string,
362a06e3
PG
375 "%d", value);
376 len_string -= len_written;
377 ptr += len_written;
034cdee9
PG
378 break;
379 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
47555ee9
PG
380 /* limitation: stop converting */
381 if (*error == -2)
382 break;
383 mval->value = value;
384 if (op[6] == 1) {
385 /* different from */
386 mval->compare_operator |=
387 OPERATOR_COMPARE_LESS_THAN;
388 mval->compare_operator |=
389 OPERATOR_COMPARE_GREATER_THAN;
390 } else
391 mval->compare_operator |=
392 OPERATOR_COMPARE_EQUAL_TO;
393 if (op[7] == 1)
394 mval->compare_operator |=
395 OPERATOR_COMPARE_EXACT_MATCH;
396 if (op[1] == 1)
397 mval->unary_operator =
398 OPERATOR_UNARY_AND;
399 else
400 mval->unary_operator =
401 OPERATOR_UNARY_OR;
402 mval++;
034cdee9
PG
403 break;
404 case BGP_FLOWSPEC_VALIDATE_ONLY:
405 default:
406 /* no action */
407 break;
408 }
409 offset += value_size;
410 loop++;
411 } while (op[0] == 0 && offset < max_len - 1);
412 if (offset > max_len)
413 *error = -1;
414 /* use error parameter to count the number of entries */
415 if (*error == 0)
416 *error = loop;
417 return offset;
418}
419
47555ee9
PG
420int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
421 struct bgp_pbr_entry_main *bpem)
98a9dbc7 422{
47555ee9
PG
423 int offset = 0, error = 0;
424 struct prefix *prefix;
425 struct bgp_pbr_match_val *mval;
426 uint8_t *match_num;
427 uint8_t bitmask = 0;
428 int ret = 0, type;
98a9dbc7 429
47555ee9 430 while (offset < len - 1 && error >= 0) {
98a9dbc7
PG
431 type = nlri_content[offset];
432 offset++;
433 switch (type) {
434 case FLOWSPEC_DEST_PREFIX:
435 case FLOWSPEC_SRC_PREFIX:
47555ee9
PG
436 bitmask = 0;
437 if (type == FLOWSPEC_DEST_PREFIX) {
438 bitmask |= PREFIX_DST_PRESENT;
439 prefix = &bpem->dst_prefix;
440 } else {
441 bitmask |= PREFIX_SRC_PRESENT;
442 prefix = &bpem->src_prefix;
443 }
98a9dbc7
PG
444 ret = bgp_flowspec_ip_address(
445 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
47555ee9 446 nlri_content + offset,
98a9dbc7 447 len - offset,
47555ee9
PG
448 prefix, &error);
449 if (error < 0)
af4c2728 450 flog_err(BGP_ERR_FLOWSPEC_PACKET,
4f3be667
DS
451 "%s: flowspec_ip_address error %d",
452 __func__, error);
47555ee9
PG
453 else
454 bpem->match_bitmask |= bitmask;
455 offset += ret;
98a9dbc7
PG
456 break;
457 case FLOWSPEC_IP_PROTOCOL:
47555ee9
PG
458 match_num = &(bpem->match_protocol_num);
459 mval = (struct bgp_pbr_match_val *)
460 &(bpem->protocol);
461 offset += bgp_flowspec_call_non_opaque_decode(
462 nlri_content + offset,
463 len - offset,
464 mval, match_num,
465 &error);
466 break;
98a9dbc7 467 case FLOWSPEC_PORT:
47555ee9
PG
468 match_num = &(bpem->match_port_num);
469 mval = (struct bgp_pbr_match_val *)
470 &(bpem->port);
471 offset += bgp_flowspec_call_non_opaque_decode(
472 nlri_content + offset,
473 len - offset,
474 mval, match_num,
475 &error);
476 break;
98a9dbc7 477 case FLOWSPEC_DEST_PORT:
47555ee9
PG
478 match_num = &(bpem->match_dst_port_num);
479 mval = (struct bgp_pbr_match_val *)
480 &(bpem->dst_port);
481 offset += bgp_flowspec_call_non_opaque_decode(
482 nlri_content + offset,
483 len - offset,
484 mval, match_num,
485 &error);
486 break;
98a9dbc7 487 case FLOWSPEC_SRC_PORT:
47555ee9
PG
488 match_num = &(bpem->match_src_port_num);
489 mval = (struct bgp_pbr_match_val *)
490 &(bpem->src_port);
491 offset += bgp_flowspec_call_non_opaque_decode(
492 nlri_content + offset,
493 len - offset,
494 mval, match_num,
495 &error);
496 break;
98a9dbc7 497 case FLOWSPEC_ICMP_TYPE:
47555ee9
PG
498 match_num = &(bpem->match_icmp_type_num);
499 mval = (struct bgp_pbr_match_val *)
500 &(bpem->icmp_type);
501 offset += bgp_flowspec_call_non_opaque_decode(
502 nlri_content + offset,
503 len - offset,
504 mval, match_num,
505 &error);
98a9dbc7 506 break;
47555ee9
PG
507 case FLOWSPEC_ICMP_CODE:
508 match_num = &(bpem->match_icmp_code_num);
509 mval = (struct bgp_pbr_match_val *)
510 &(bpem->icmp_code);
511 offset += bgp_flowspec_call_non_opaque_decode(
512 nlri_content + offset,
513 len - offset,
514 mval, match_num,
515 &error);
98a9dbc7
PG
516 break;
517 case FLOWSPEC_PKT_LEN:
47555ee9
PG
518 match_num =
519 &(bpem->match_packet_length_num);
520 mval = (struct bgp_pbr_match_val *)
521 &(bpem->packet_length);
522 offset += bgp_flowspec_call_non_opaque_decode(
523 nlri_content + offset,
524 len - offset,
525 mval, match_num,
526 &error);
527 break;
98a9dbc7 528 case FLOWSPEC_DSCP:
47555ee9
PG
529 match_num = &(bpem->match_dscp_num);
530 mval = (struct bgp_pbr_match_val *)
531 &(bpem->dscp);
532 offset += bgp_flowspec_call_non_opaque_decode(
533 nlri_content + offset,
534 len - offset,
535 mval, match_num,
536 &error);
537 break;
538 case FLOWSPEC_TCP_FLAGS:
588ec356 539 ret = bgp_flowspec_bitmask_decode(
47555ee9
PG
540 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
541 nlri_content + offset,
542 len - offset,
543 &bpem->tcpflags, &error);
544 if (error < 0)
af4c2728 545 flog_err(BGP_ERR_FLOWSPEC_PACKET,
4f3be667
DS
546 "%s: flowspec_tcpflags_decode error %d",
547 __func__, error);
47555ee9
PG
548 else
549 bpem->match_tcpflags_num = error;
550 /* contains the number of slots used */
551 offset += ret;
98a9dbc7
PG
552 break;
553 case FLOWSPEC_FRAGMENT:
588ec356 554 ret = bgp_flowspec_bitmask_decode(
47555ee9
PG
555 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
556 nlri_content + offset,
557 len - offset, &bpem->fragment,
558 &error);
559 if (error < 0)
af4c2728 560 flog_err(BGP_ERR_FLOWSPEC_PACKET,
4f3be667
DS
561 "%s: flowspec_fragment_type_decode error %d",
562 __func__, error);
47555ee9 563 else
588ec356 564 bpem->match_fragment_num = error;
47555ee9 565 offset += ret;
98a9dbc7
PG
566 break;
567 default:
af4c2728 568 flog_err(LIB_ERR_DEVELOPMENT, "%s: unknown type %d\n",
02705213 569 __func__, type);
98a9dbc7 570 }
98a9dbc7 571 }
47555ee9 572 return error;
98a9dbc7 573}