]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_flowspec_util.c
lib: enforce vrf_name_to_id by returning default_vrf when name is null
[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)
e50f7cfd 71 flog_err(EC_BGP_FLOWSPEC_PACKET,
1c50c1c0 72 "%s: flowspec_op_decode error %d", __func__, *error);
47555ee9
PG
73 else
74 *match_num = *error;
75 return ret;
76}
77
63a0b7a9
PG
78bool bgp_flowspec_contains_prefix(struct prefix *pfs,
79 struct prefix *input,
80 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
457 && prefix->u.prefix4.s_addr == 0)
458 memset(prefix, 0,
459 sizeof(struct prefix));
460 else
461 bpem->match_bitmask |= bitmask;
462 }
47555ee9 463 offset += ret;
98a9dbc7
PG
464 break;
465 case FLOWSPEC_IP_PROTOCOL:
47555ee9
PG
466 match_num = &(bpem->match_protocol_num);
467 mval = (struct bgp_pbr_match_val *)
468 &(bpem->protocol);
469 offset += bgp_flowspec_call_non_opaque_decode(
470 nlri_content + offset,
471 len - offset,
472 mval, match_num,
473 &error);
474 break;
98a9dbc7 475 case FLOWSPEC_PORT:
47555ee9
PG
476 match_num = &(bpem->match_port_num);
477 mval = (struct bgp_pbr_match_val *)
478 &(bpem->port);
479 offset += bgp_flowspec_call_non_opaque_decode(
480 nlri_content + offset,
481 len - offset,
482 mval, match_num,
483 &error);
484 break;
98a9dbc7 485 case FLOWSPEC_DEST_PORT:
47555ee9
PG
486 match_num = &(bpem->match_dst_port_num);
487 mval = (struct bgp_pbr_match_val *)
488 &(bpem->dst_port);
489 offset += bgp_flowspec_call_non_opaque_decode(
490 nlri_content + offset,
491 len - offset,
492 mval, match_num,
493 &error);
494 break;
98a9dbc7 495 case FLOWSPEC_SRC_PORT:
47555ee9
PG
496 match_num = &(bpem->match_src_port_num);
497 mval = (struct bgp_pbr_match_val *)
498 &(bpem->src_port);
499 offset += bgp_flowspec_call_non_opaque_decode(
500 nlri_content + offset,
501 len - offset,
502 mval, match_num,
503 &error);
504 break;
98a9dbc7 505 case FLOWSPEC_ICMP_TYPE:
47555ee9
PG
506 match_num = &(bpem->match_icmp_type_num);
507 mval = (struct bgp_pbr_match_val *)
508 &(bpem->icmp_type);
509 offset += bgp_flowspec_call_non_opaque_decode(
510 nlri_content + offset,
511 len - offset,
512 mval, match_num,
513 &error);
98a9dbc7 514 break;
47555ee9
PG
515 case FLOWSPEC_ICMP_CODE:
516 match_num = &(bpem->match_icmp_code_num);
517 mval = (struct bgp_pbr_match_val *)
518 &(bpem->icmp_code);
519 offset += bgp_flowspec_call_non_opaque_decode(
520 nlri_content + offset,
521 len - offset,
522 mval, match_num,
523 &error);
98a9dbc7
PG
524 break;
525 case FLOWSPEC_PKT_LEN:
47555ee9
PG
526 match_num =
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,
532 len - offset,
533 mval, match_num,
534 &error);
535 break;
98a9dbc7 536 case FLOWSPEC_DSCP:
47555ee9
PG
537 match_num = &(bpem->match_dscp_num);
538 mval = (struct bgp_pbr_match_val *)
539 &(bpem->dscp);
540 offset += bgp_flowspec_call_non_opaque_decode(
541 nlri_content + offset,
542 len - offset,
543 mval, match_num,
544 &error);
545 break;
546 case FLOWSPEC_TCP_FLAGS:
588ec356 547 ret = bgp_flowspec_bitmask_decode(
47555ee9
PG
548 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
549 nlri_content + offset,
550 len - offset,
551 &bpem->tcpflags, &error);
552 if (error < 0)
1c50c1c0
QY
553 flog_err(
554 EC_BGP_FLOWSPEC_PACKET,
555 "%s: flowspec_tcpflags_decode error %d",
556 __func__, error);
47555ee9
PG
557 else
558 bpem->match_tcpflags_num = error;
559 /* contains the number of slots used */
560 offset += ret;
98a9dbc7
PG
561 break;
562 case FLOWSPEC_FRAGMENT:
588ec356 563 ret = bgp_flowspec_bitmask_decode(
47555ee9
PG
564 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
565 nlri_content + offset,
566 len - offset, &bpem->fragment,
567 &error);
568 if (error < 0)
1c50c1c0
QY
569 flog_err(
570 EC_BGP_FLOWSPEC_PACKET,
571 "%s: flowspec_fragment_type_decode error %d",
572 __func__, error);
47555ee9 573 else
588ec356 574 bpem->match_fragment_num = error;
47555ee9 575 offset += ret;
98a9dbc7
PG
576 break;
577 default:
450971aa 578 flog_err(EC_LIB_DEVELOPMENT, "%s: unknown type %d\n",
1c50c1c0 579 __func__, type);
98a9dbc7 580 }
98a9dbc7 581 }
47555ee9 582 return error;
98a9dbc7 583}