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