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