]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_flowspec_util.c
bgpd: BGP_[WARN|ERR] -> EC_BGP
[mirror_frr.git] / bgpd / bgp_flowspec_util.c
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"
24 #include "lib_errors.h"
25
26 #include "bgp_table.h"
27 #include "bgp_flowspec_util.h"
28 #include "bgp_flowspec_private.h"
29 #include "bgp_pbr.h"
30 #include "bgp_errors.h"
31
32 static 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
46 static 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
56 /* call bgp_flowspec_op_decode
57 * returns offset
58 */
59 static 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)
71 flog_err(EC_BGP_FLOWSPEC_PACKET,
72 "%s: flowspec_op_decode error %d",
73 __func__, *error);
74 else
75 *match_num = *error;
76 return ret;
77 }
78
79 bool bgp_flowspec_contains_prefix(struct prefix *pfs,
80 struct prefix *input,
81 int prefix_check)
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;
130 case FLOWSPEC_FRAGMENT:
131 case FLOWSPEC_TCP_FLAGS:
132 ret = bgp_flowspec_bitmask_decode(
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;
146 default:
147 error = -1;
148 break;
149 }
150 offset += ret;
151 }
152 return false;
153 }
154
155 /*
156 * handle the flowspec address src/dst or generic address NLRI
157 * return number of bytes analysed ( >= 0).
158 */
159 int 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,
211 * if result is a string, its assumed length
212 * is BGP_FLOWSPEC_STRING_DISPLAY_MAX
213 */
214 int 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;
224 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
225 int len_written;
226 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
227
228 *error = 0;
229 do {
230 if (loop > BGP_PBR_MATCH_VAL_MAX)
231 *error = -2;
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:
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;
273 break;
274 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
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++;
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 /*
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
318 */
319 int bgp_flowspec_bitmask_decode(enum bgp_flowspec_util_nlri_t type,
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 */
327 struct bgp_pbr_match_val *mval = (struct bgp_pbr_match_val *)result;
328 uint32_t offset = 0;
329 int len_string = BGP_FLOWSPEC_STRING_DISPLAY_MAX;
330 int len_written;
331
332 *error = 0;
333 do {
334 if (loop > BGP_PBR_MATCH_VAL_MAX)
335 *error = -2;
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:
346 if (op[1] == 1 && loop != 0) {
347 len_written = snprintf(ptr, len_string,
348 ",&");
349 len_string -= len_written;
350 ptr += len_written;
351 } else if (op[1] == 0 && loop != 0) {
352 len_written = snprintf(ptr, len_string,
353 ",|");
354 len_string -= len_written;
355 ptr += len_written;
356 }
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 "∋ ");
365 len_string -= len_written;
366 ptr += len_written;
367 }
368 if (op[6] == 1) {
369 len_written = snprintf(ptr, len_string,
370 "! ");
371 len_string -= len_written;
372 ptr += len_written;
373 }
374 len_written = snprintf(ptr, len_string,
375 "%d", value);
376 len_string -= len_written;
377 ptr += len_written;
378 break;
379 case BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE:
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++;
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
420 int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
421 struct bgp_pbr_entry_main *bpem)
422 {
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;
429
430 while (offset < len - 1 && error >= 0) {
431 type = nlri_content[offset];
432 offset++;
433 switch (type) {
434 case FLOWSPEC_DEST_PREFIX:
435 case FLOWSPEC_SRC_PREFIX:
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 }
444 ret = bgp_flowspec_ip_address(
445 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
446 nlri_content + offset,
447 len - offset,
448 prefix, &error);
449 if (error < 0)
450 flog_err(EC_BGP_FLOWSPEC_PACKET,
451 "%s: flowspec_ip_address error %d",
452 __func__, error);
453 else
454 bpem->match_bitmask |= bitmask;
455 offset += ret;
456 break;
457 case FLOWSPEC_IP_PROTOCOL:
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;
467 case FLOWSPEC_PORT:
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;
477 case FLOWSPEC_DEST_PORT:
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;
487 case FLOWSPEC_SRC_PORT:
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;
497 case FLOWSPEC_ICMP_TYPE:
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);
506 break;
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);
516 break;
517 case FLOWSPEC_PKT_LEN:
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;
528 case FLOWSPEC_DSCP:
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:
539 ret = bgp_flowspec_bitmask_decode(
540 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
541 nlri_content + offset,
542 len - offset,
543 &bpem->tcpflags, &error);
544 if (error < 0)
545 flog_err(EC_BGP_FLOWSPEC_PACKET,
546 "%s: flowspec_tcpflags_decode error %d",
547 __func__, error);
548 else
549 bpem->match_tcpflags_num = error;
550 /* contains the number of slots used */
551 offset += ret;
552 break;
553 case FLOWSPEC_FRAGMENT:
554 ret = bgp_flowspec_bitmask_decode(
555 BGP_FLOWSPEC_CONVERT_TO_NON_OPAQUE,
556 nlri_content + offset,
557 len - offset, &bpem->fragment,
558 &error);
559 if (error < 0)
560 flog_err(EC_BGP_FLOWSPEC_PACKET,
561 "%s: flowspec_fragment_type_decode error %d",
562 __func__, error);
563 else
564 bpem->match_fragment_num = error;
565 offset += ret;
566 break;
567 default:
568 flog_err(LIB_ERR_DEVELOPMENT, "%s: unknown type %d\n",
569 __func__, type);
570 }
571 }
572 return error;
573 }