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