]> git.ipfire.org Git - thirdparty/bird.git/blob - lib/flowspec.c
Filter: Add support for src/dst accessors for Flowspec and SADR
[thirdparty/bird.git] / lib / flowspec.c
1 /*
2 * BIRD Library -- Flow specification (RFC 5575)
3 *
4 * (c) 2016 CZ.NIC z.s.p.o.
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 /**
10 * DOC: Flow specification (flowspec)
11 *
12 * Flowspec are rules (RFC 5575) for firewalls disseminated using BGP protocol.
13 * The |flowspec.c| is a library for handling flowspec binary streams and
14 * flowspec data structures. You will find there functions for validation
15 * incoming flowspec binary streams, iterators for jumping over components,
16 * functions for handling a length and functions for formatting flowspec data
17 * structure into user-friendly text representation.
18 *
19 * In this library, you will find also flowspec builder. In |confbase.Y|, there
20 * are grammar's rules for parsing and building new flowspec data structure
21 * from BIRD's configuration files and from BIRD's command line interface.
22 * Finalize function will assemble final &net_addr_flow4 or &net_addr_flow6
23 * data structure.
24 *
25 * The data structures &net_addr_flow4 and &net_addr_flow6 are defined in
26 * |net.h| file. The attribute length is size of whole data structure plus
27 * binary stream representation of flowspec including a compressed encoded
28 * length of flowspec.
29 *
30 * Sometimes in code, it is used expression flowspec type, it should mean
31 * flowspec component type.
32 */
33
34 #include "nest/bird.h"
35 #include "lib/flowspec.h"
36 #include "conf/conf.h"
37
38
39 static const char* flow4_type_str[] = {
40 [FLOW_TYPE_DST_PREFIX] = "dst",
41 [FLOW_TYPE_SRC_PREFIX] = "src",
42 [FLOW_TYPE_IP_PROTOCOL] = "proto",
43 [FLOW_TYPE_PORT] = "port",
44 [FLOW_TYPE_DST_PORT] = "dport",
45 [FLOW_TYPE_SRC_PORT] = "sport",
46 [FLOW_TYPE_ICMP_TYPE] = "icmp type",
47 [FLOW_TYPE_ICMP_CODE] = "icmp code",
48 [FLOW_TYPE_TCP_FLAGS] = "tcp flags",
49 [FLOW_TYPE_PACKET_LENGTH] = "length",
50 [FLOW_TYPE_DSCP] = "dscp",
51 [FLOW_TYPE_FRAGMENT] = "fragment"
52 };
53
54 static const char* flow6_type_str[] = {
55 [FLOW_TYPE_DST_PREFIX] = "dst",
56 [FLOW_TYPE_SRC_PREFIX] = "src",
57 [FLOW_TYPE_NEXT_HEADER] = "next header",
58 [FLOW_TYPE_PORT] = "port",
59 [FLOW_TYPE_DST_PORT] = "dport",
60 [FLOW_TYPE_SRC_PORT] = "sport",
61 [FLOW_TYPE_ICMP_TYPE] = "icmp type",
62 [FLOW_TYPE_ICMP_CODE] = "icmp code",
63 [FLOW_TYPE_TCP_FLAGS] = "tcp flags",
64 [FLOW_TYPE_PACKET_LENGTH] = "length",
65 [FLOW_TYPE_DSCP] = "dscp",
66 [FLOW_TYPE_FRAGMENT] = "fragment",
67 [FLOW_TYPE_LABEL] = "label"
68 };
69
70 /**
71 * flow_type_str - get stringified flowspec name of component
72 * @type: flowspec component type
73 * @ipv6: IPv4/IPv6 decide flag, use zero for IPv4 and one for IPv6
74 *
75 * This function returns flowspec name of component @type in string.
76 */
77 const char *
78 flow_type_str(enum flow_type type, int ipv6)
79 {
80 return ipv6 ? flow6_type_str[type] : flow4_type_str[type];
81 }
82
83 /*
84 * Length
85 */
86
87 /**
88 * flow_write_length - write compressed length value
89 * @data: destination buffer to write
90 * @len: the value of the length (0 to 0xfff) for writing
91 *
92 * This function writes appropriate as (1- or 2-bytes) the value of @len into
93 * buffer @data. The function returns number of written bytes, thus 1 or 2 bytes.
94 */
95 uint
96 flow_write_length(byte *data, u16 len)
97 {
98 if (len >= 0xf0)
99 {
100 put_u16(data, len | 0xf000);
101 return 2;
102 }
103
104 *data = len;
105 return 1;
106 }
107
108 inline static uint
109 get_value_length(const byte *op)
110 {
111 return (1 << ((*op & 0x30) >> 4));
112 }
113
114
115 /*
116 * Flowspec iterators
117 */
118
119 static inline u8 num_op(const byte *op) { return (*op & 0x07); }
120 static inline int isset_and(const byte *op) { return ((*op & 0x40) == 0x40); }
121 static inline int isset_end(const byte *op) { return ((*op & 0x80) == 0x80); }
122
123 static const byte *
124 flow_first_part(const byte *data)
125 {
126 if (!data || flow_read_length(data) == 0)
127 return NULL;
128
129 /* It is allowed to encode the value of length less then 240 into 2-bytes too */
130 if ((data[0] & 0xf0) == 0xf0)
131 return data + 2;
132
133 return data + 1;
134 }
135
136 /**
137 * flow4_first_part - get position of the first flowspec component
138 * @f: flowspec data structure &net_addr_flow4
139 *
140 * This function return a position to the beginning of the first flowspec
141 * component in IPv4 flowspec @f.
142 */
143 inline const byte *
144 flow4_first_part(const net_addr_flow4 *f)
145 {
146 return f ? flow_first_part(f->data) : NULL;
147 }
148
149 /**
150 * flow6_first_part - get position of the first flowspec component
151 * @f: flowspec data structure &net_addr_flow6
152 *
153 * This function return a position to the beginning of the first flowspec
154 * component in IPv6 flowspec @f.
155 */
156 inline const byte *
157 flow6_first_part(const net_addr_flow6 *f)
158 {
159 return f ? flow_first_part(f->data) : NULL;
160 }
161
162 static const byte *
163 flow_next_part(const byte *pos, const byte *end, int ipv6)
164 {
165 switch (*pos++)
166 {
167 case FLOW_TYPE_DST_PREFIX:
168 case FLOW_TYPE_SRC_PREFIX:
169 {
170 uint pxlen = *pos++;
171 uint bytes = BYTES(pxlen);
172 if (ipv6)
173 {
174 uint offset = *pos++ / 8;
175 pos += bytes - offset;
176 }
177 else
178 {
179 pos += bytes;
180 }
181 break;
182 }
183
184 case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
185 case FLOW_TYPE_PORT:
186 case FLOW_TYPE_DST_PORT:
187 case FLOW_TYPE_SRC_PORT:
188 case FLOW_TYPE_ICMP_TYPE:
189 case FLOW_TYPE_ICMP_CODE:
190 case FLOW_TYPE_TCP_FLAGS:
191 case FLOW_TYPE_PACKET_LENGTH:
192 case FLOW_TYPE_DSCP:
193 case FLOW_TYPE_FRAGMENT:
194 case FLOW_TYPE_LABEL:
195 {
196 /* Is this the end of list operator-value pair? */
197 uint last = 0;
198
199 while (!last)
200 {
201 last = isset_end(pos);
202
203 /* Value length of operator */
204 uint len = get_value_length(pos);
205 pos += 1+len;
206 }
207 break;
208 }
209 default:
210 return NULL;
211 }
212
213 return (pos < end) ? pos : NULL;
214 }
215
216 /**
217 * flow4_next_part - an iterator over flowspec components in flowspec binary stream
218 * @pos: the beginning of a previous or the first component in flowspec binary
219 * stream
220 * @end: the last valid byte in scanned flowspec binary stream
221 *
222 * This function returns a position to the beginning of the next component
223 * (to a component type byte) in flowspec binary stream or %NULL for the end.
224 */
225 inline const byte *
226 flow4_next_part(const byte *pos, const byte *end)
227 {
228 return flow_next_part(pos, end, 0);
229 }
230
231 /**
232 * flow6_next_part - an iterator over flowspec components in flowspec binary stream
233 * @pos: the beginning of a previous or the first component in flowspec binary
234 * stream
235 * @end: the last valid byte in scanned flowspec binary stream
236 *
237 * This function returns a position to the beginning of the next component
238 * (to a component type byte) in flowspec binary stream or %NULL for the end.
239 */
240 inline const byte *
241 flow6_next_part(const byte *pos, const byte *end)
242 {
243 return flow_next_part(pos, end, 1);
244 }
245
246 static const byte *
247 flow_get_part(const byte *data, uint dlen, uint type, int ipv6)
248 {
249 const byte *part;
250
251 for (part = flow_first_part(data);
252 part && (part[0] <= type);
253 part = flow_next_part(part, data+dlen, ipv6))
254 if (part[0] == type)
255 return part;
256
257 return NULL;
258 }
259
260 const byte *
261 flow4_get_part(const net_addr_flow4 *f, uint type)
262 {
263 return flow_get_part(f->data, f->length - sizeof(net_addr_flow4), type, 0);
264 }
265
266 const byte *
267 flow6_get_part(const net_addr_flow6 *f, uint type)
268 {
269 return flow_get_part(f->data, f->length - sizeof(net_addr_flow6), type, 1);
270 }
271
272
273 /*
274 * Flowspec accessors
275 */
276
277 static inline ip4_addr
278 flow_read_ip4(const byte *px, uint pxlen)
279 {
280 ip4_addr ip = IP4_NONE;
281 memcpy(&ip, px, BYTES(pxlen));
282 return ip4_ntoh(ip);
283 }
284
285 ip4_addr
286 flow_read_ip4_part(const byte *part)
287 {
288 return flow_read_ip4(part + 2, part[1]);
289 }
290
291 static inline ip6_addr
292 flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
293 {
294 uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
295 uint ceil_len = BYTES(pxlen);
296 ip6_addr ip = IP6_NONE;
297
298 memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
299
300 return ip6_ntoh(ip);
301 }
302
303 ip6_addr
304 flow_read_ip6_part(const byte *part)
305 {
306 return flow_read_ip6(part + 3, part[1], part[2]);
307 }
308
309
310 /*
311 * Flowspec validation
312 */
313
314 static const char* flow_validated_state_str_[] = {
315 [FLOW_ST_UNKNOWN_COMPONENT] = "Unknown component",
316 [FLOW_ST_VALID] = "Valid",
317 [FLOW_ST_NOT_COMPLETE] = "Not complete",
318 [FLOW_ST_EXCEED_MAX_PREFIX_LENGTH] = "Exceed maximal prefix length",
319 [FLOW_ST_EXCEED_MAX_PREFIX_OFFSET] = "Exceed maximal prefix offset",
320 [FLOW_ST_EXCEED_MAX_VALUE_LENGTH] = "Exceed maximal value length",
321 [FLOW_ST_BAD_TYPE_ORDER] = "Bad component order",
322 [FLOW_ST_AND_BIT_SHOULD_BE_UNSET] = "The AND-bit should be unset",
323 [FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED] = "The Zero-bit should be unset",
324 [FLOW_ST_DEST_PREFIX_REQUIRED] = "Destination prefix is missing",
325 [FLOW_ST_INVALID_TCP_FLAGS] = "TCP flags exceeding 0xfff",
326 [FLOW_ST_CANNOT_USE_DONT_FRAGMENT] = "Cannot use Don't fragment flag in IPv6 flow"
327 };
328
329 /**
330 * flow_validated_state_str - return a textual description of validation process
331 * @code: validation result
332 *
333 * This function return well described validation state in string.
334 */
335 const char *
336 flow_validated_state_str(enum flow_validated_state code)
337 {
338 return flow_validated_state_str_[code];
339 }
340
341 static const u8 flow4_max_value_length[] = {
342 [FLOW_TYPE_DST_PREFIX] = 0,
343 [FLOW_TYPE_SRC_PREFIX] = 0,
344 [FLOW_TYPE_IP_PROTOCOL] = 1,
345 [FLOW_TYPE_PORT] = 2,
346 [FLOW_TYPE_DST_PORT] = 2,
347 [FLOW_TYPE_SRC_PORT] = 2,
348 [FLOW_TYPE_ICMP_TYPE] = 1,
349 [FLOW_TYPE_ICMP_CODE] = 1,
350 [FLOW_TYPE_TCP_FLAGS] = 2,
351 [FLOW_TYPE_PACKET_LENGTH] = 2,
352 [FLOW_TYPE_DSCP] = 1,
353 [FLOW_TYPE_FRAGMENT] = 1 /* XXX */
354 };
355
356 static const u8 flow6_max_value_length[] = {
357 [FLOW_TYPE_DST_PREFIX] = 0,
358 [FLOW_TYPE_SRC_PREFIX] = 0,
359 [FLOW_TYPE_NEXT_HEADER] = 1,
360 [FLOW_TYPE_PORT] = 2,
361 [FLOW_TYPE_DST_PORT] = 2,
362 [FLOW_TYPE_SRC_PORT] = 2,
363 [FLOW_TYPE_ICMP_TYPE] = 1,
364 [FLOW_TYPE_ICMP_CODE] = 1,
365 [FLOW_TYPE_TCP_FLAGS] = 2,
366 [FLOW_TYPE_PACKET_LENGTH] = 2,
367 [FLOW_TYPE_DSCP] = 1,
368 [FLOW_TYPE_FRAGMENT] = 1, /* XXX */
369 [FLOW_TYPE_LABEL] = 4
370 };
371
372 static u8
373 flow_max_value_length(enum flow_type type, int ipv6)
374 {
375 return ipv6 ? flow6_max_value_length[type] : flow4_max_value_length[type];
376 }
377
378 /**
379 * flow_check_cf_bmk_values - check value/bitmask part of flowspec component
380 * @fb: flow builder instance
381 * @neg: negation operand
382 * @val: value from value/mask pair
383 * @mask: bitmap mask from value/mask pair
384 *
385 * This function checks value/bitmask pair. If some problem will appear, the
386 * function calls cf_error() function with a textual description of reason
387 * to failing of validation.
388 */
389 void
390 flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask)
391 {
392 flow_check_cf_value_length(fb, val);
393 flow_check_cf_value_length(fb, mask);
394
395 if (neg && !(val == 0 || val == mask))
396 cf_error("For negation, value must be zero or bitmask");
397
398 if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & 0xf000))
399 cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask);
400
401 if ((fb->this_type == FLOW_TYPE_FRAGMENT) && fb->ipv6 && (mask & 0x01))
402 cf_error("Invalid mask 0x%x, bit 0 must be 0", mask);
403
404 if (val & ~mask)
405 cf_error("Value 0x%x outside bitmask 0x%x", val, mask);
406 }
407
408 /**
409 * flow_check_cf_value_length - check value by flowspec component type
410 * @fb: flow builder instance
411 * @val: value
412 *
413 * This function checks if the value is in range of component's type support.
414 * If some problem will appear, the function calls cf_error() function with
415 * a textual description of reason to failing of validation.
416 */
417 void
418 flow_check_cf_value_length(struct flow_builder *fb, u32 val)
419 {
420 enum flow_type t = fb->this_type;
421 u8 max = flow_max_value_length(t, fb->ipv6);
422
423 if (t == FLOW_TYPE_DSCP && val > 0x3f)
424 cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val);
425
426 if (max == 1 && (val > 0xff))
427 cf_error("%s value %u out of range (0-255)", flow_type_str(t, fb->ipv6), val);
428
429 if (max == 2 && (val > 0xffff))
430 cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
431 }
432
433 static enum flow_validated_state
434 flow_validate(const byte *nlri, uint len, int ipv6)
435 {
436 enum flow_type type = 0;
437 const byte *pos = nlri;
438 const byte *end = nlri + len;
439 int met_dst_pfx = 0;
440
441 while (pos < end)
442 {
443 /* Check increasing type ordering */
444 if (*pos <= type)
445 return FLOW_ST_BAD_TYPE_ORDER;
446 type = *pos++;
447
448 switch (type)
449 {
450 case FLOW_TYPE_DST_PREFIX:
451 met_dst_pfx = 1;
452 /* Fall through */
453 case FLOW_TYPE_SRC_PREFIX:
454 {
455 uint pxlen = *pos++;
456 if (pxlen > (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
457 return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
458
459 uint bytes = BYTES(pxlen);
460 if (ipv6)
461 {
462 uint pxoffset = *pos++;
463 if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
464 return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
465 bytes -= pxoffset / 8;
466 }
467 pos += bytes;
468
469 break;
470 }
471
472 case FLOW_TYPE_LABEL:
473 if (!ipv6)
474 return FLOW_ST_UNKNOWN_COMPONENT;
475 /* fall through */
476 case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
477 case FLOW_TYPE_PORT:
478 case FLOW_TYPE_DST_PORT:
479 case FLOW_TYPE_SRC_PORT:
480 case FLOW_TYPE_ICMP_TYPE:
481 case FLOW_TYPE_ICMP_CODE:
482 case FLOW_TYPE_TCP_FLAGS:
483 case FLOW_TYPE_PACKET_LENGTH:
484 case FLOW_TYPE_DSCP:
485 case FLOW_TYPE_FRAGMENT:
486 {
487 uint last = 0;
488 uint first = 1;
489
490 while (!last)
491 {
492 /*
493 * 0 1 2 3 4 5 6 7
494 * +---+---+---+---+---+---+---+---+
495 * | e | a | len | 0 |lt |gt |eq |
496 * +---+---+---+---+---+---+---+---+
497 *
498 * Numeric operator
499 */
500
501 last = isset_end(pos);
502
503 /* The AND bit should in the first operator byte of a sequence */
504 if (first && isset_and(pos))
505 return FLOW_ST_AND_BIT_SHOULD_BE_UNSET;
506
507 /* This bit should be zero */
508 if (*pos & 0x08)
509 return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
510
511 if (type == FLOW_TYPE_TCP_FLAGS || type == FLOW_TYPE_FRAGMENT)
512 {
513 /*
514 * 0 1 2 3 4 5 6 7
515 * +---+---+---+---+---+---+---+---+
516 * | e | a | len | 0 | 0 |not| m |
517 * +---+---+---+---+---+---+---+---+
518 *
519 * Bitmask operand
520 */
521 if (*pos & 0x04)
522 return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
523 }
524
525 /* Value length of operator */
526 uint len = get_value_length(pos);
527 if (len > flow_max_value_length(type, ipv6))
528 return FLOW_ST_EXCEED_MAX_VALUE_LENGTH;
529
530 /* TCP Flags component must not check highest nibble (just 12 valid bits) */
531 if ((type == FLOW_TYPE_TCP_FLAGS) && (len == 2) && (pos[1] & 0xf0))
532 return FLOW_ST_INVALID_TCP_FLAGS;
533
534 /* Bit-7 must be 0 [draft-ietf-idr-flow-spec-v6] */
535 if ((type == FLOW_TYPE_FRAGMENT) && ipv6 && (pos[1] & 0x01))
536 return FLOW_ST_CANNOT_USE_DONT_FRAGMENT;
537 /* XXX: Could be a fragment component encoded in 2-bytes? */
538
539 pos += 1+len;
540
541 if (pos > end && !last)
542 return FLOW_ST_NOT_COMPLETE;
543
544 if (pos > (end+1))
545 return FLOW_ST_NOT_COMPLETE;
546
547 first = 0;
548 }
549 break;
550 }
551 default:
552 return FLOW_ST_UNKNOWN_COMPONENT;
553 }
554 }
555
556 if (pos != end)
557 return FLOW_ST_NOT_COMPLETE;
558
559 if (!ipv6 && !met_dst_pfx)
560 return FLOW_ST_DEST_PREFIX_REQUIRED;
561
562 return FLOW_ST_VALID;
563 }
564
565 /**
566 * flow4_validate - check untrustworthy IPv4 flowspec data stream
567 * @nlri: flowspec data stream without compressed encoded length value
568 * @len: length of @nlri
569 *
570 * This function checks meaningfulness of binary flowspec. It should return
571 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
572 * returns some other %FLOW_ST_xxx state.
573 */
574 inline enum flow_validated_state
575 flow4_validate(const byte *nlri, uint len)
576 {
577 return flow_validate(nlri, len, 0);
578 }
579
580 /**
581 * flow6_validate - check untrustworthy IPv6 flowspec data stream
582 * @nlri: flowspec binary stream without encoded length value
583 * @len: length of @nlri
584 *
585 * This function checks meaningfulness of binary flowspec. It should return
586 * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
587 * returns some other %FLOW_ST_xxx state.
588 */
589 inline enum flow_validated_state
590 flow6_validate(const byte *nlri, uint len)
591 {
592 return flow_validate(nlri, len, 1);
593 }
594
595 /**
596 * flow4_validate_cf - validate flowspec data structure &net_addr_flow4 in parsing time
597 * @f: flowspec data structure &net_addr_flow4
598 *
599 * Check if @f is valid flowspec data structure. Can call cf_error() function
600 * with a textual description of reason to failing of validation.
601 */
602 void
603 flow4_validate_cf(net_addr_flow4 *f)
604 {
605 enum flow_validated_state r = flow4_validate(flow4_first_part(f), flow_read_length(f->data));
606
607 if (r != FLOW_ST_VALID)
608 cf_error("Invalid flow route: %s", flow_validated_state_str(r));
609 }
610
611 /**
612 * flow6_validate_cf - validate flowspec data structure &net_addr_flow6 in parsing time
613 * @f: flowspec data structure &net_addr_flow6
614 *
615 * Check if @f is valid flowspec data structure. Can call cf_error() function
616 * with a textual description of reason to failing of validation.
617 */
618 void
619 flow6_validate_cf(net_addr_flow6 *f)
620 {
621 enum flow_validated_state r = flow6_validate(flow6_first_part(f), flow_read_length(f->data));
622
623 if (r != FLOW_ST_VALID)
624 cf_error("Invalid flow route: %s", flow_validated_state_str(r));
625 }
626
627
628 /*
629 * Flowspec Builder
630 */
631
632 /**
633 * flow_builder_init - constructor for flowspec builder instance
634 * @pool: memory pool
635 *
636 * This function prepares flowspec builder instance using memory pool @pool.
637 */
638 struct flow_builder *
639 flow_builder_init(pool *pool)
640 {
641 struct flow_builder *fb = mb_allocz(pool, sizeof(struct flow_builder));
642 BUFFER_INIT(fb->data, pool, 4);
643 return fb;
644 }
645
646 static int
647 is_stackable_type(enum flow_type type)
648 {
649 switch (type)
650 {
651 case FLOW_TYPE_IP_PROTOCOL:
652 case FLOW_TYPE_PORT:
653 case FLOW_TYPE_DST_PORT:
654 case FLOW_TYPE_SRC_PORT:
655 case FLOW_TYPE_ICMP_TYPE:
656 case FLOW_TYPE_ICMP_CODE:
657 case FLOW_TYPE_TCP_FLAGS:
658 case FLOW_TYPE_PACKET_LENGTH:
659 case FLOW_TYPE_DSCP:
660 case FLOW_TYPE_FRAGMENT:
661 case FLOW_TYPE_LABEL:
662 return 1;
663
664 default:
665 /* The unknown components are not stack-able in default */
666 return 0;
667 }
668 }
669
670 static int
671 builder_add_prepare(struct flow_builder *fb)
672 {
673 if (fb->parts[fb->this_type].length)
674 {
675 if (fb->last_type != fb->this_type)
676 return 0;
677
678 if (!is_stackable_type(fb->this_type))
679 return 0;
680 }
681 else
682 {
683 fb->parts[fb->this_type].offset = fb->data.used;
684 }
685
686 return 1;
687 }
688
689 static void
690 builder_add_finish(struct flow_builder *fb)
691 {
692 fb->parts[fb->this_type].length = fb->data.used - fb->parts[fb->this_type].offset;
693 flow_builder_set_type(fb, fb->this_type);
694 }
695
696 static void
697 push_pfx_to_buffer(struct flow_builder *fb, u8 pxlen_bytes, byte *ip)
698 {
699 for (int i = 0; i < pxlen_bytes; i++)
700 BUFFER_PUSH(fb->data) = *ip++;
701 }
702
703 /**
704 * flow_builder4_add_pfx - add IPv4 prefix
705 * @fb: flowspec builder instance
706 * @n4: net address of type IPv4
707 *
708 * This function add IPv4 prefix into flowspec builder instance.
709 */
710 int
711 flow_builder4_add_pfx(struct flow_builder *fb, const net_addr_ip4 *n4)
712 {
713 if (!builder_add_prepare(fb))
714 return 0;
715
716 ip4_addr ip4 = ip4_hton(n4->prefix);
717
718 BUFFER_PUSH(fb->data) = fb->this_type;
719 BUFFER_PUSH(fb->data) = n4->pxlen;
720 push_pfx_to_buffer(fb, BYTES(n4->pxlen), (byte *) &ip4);
721
722 builder_add_finish(fb);
723 return 1;
724 }
725
726 /**
727 * flow_builder6_add_pfx - add IPv6 prefix
728 * @fb: flowspec builder instance
729 * @n6: net address of type IPv4
730 * @pxoffset: prefix offset for @n6
731 *
732 * This function add IPv4 prefix into flowspec builder instance. This function
733 * should return 1 for successful adding, otherwise returns %0.
734 */
735 int
736 flow_builder6_add_pfx(struct flow_builder *fb, const net_addr_ip6 *n6, u32 pxoffset)
737 {
738 if (!builder_add_prepare(fb))
739 return 0;
740
741 ip6_addr ip6 = ip6_hton(n6->prefix);
742
743 BUFFER_PUSH(fb->data) = fb->this_type;
744 BUFFER_PUSH(fb->data) = n6->pxlen;
745 BUFFER_PUSH(fb->data) = pxoffset;
746 push_pfx_to_buffer(fb, BYTES(n6->pxlen) - (pxoffset / 8), ((byte *) &ip6) + (pxoffset / 8));
747
748 builder_add_finish(fb);
749 return 1;
750 }
751
752 /**
753 * flow_builder_add_op_val - add operator/value pair
754 * @fb: flowspec builder instance
755 * @op: operator
756 * @value: value
757 *
758 * This function add operator/value pair as a part of a flowspec component. It
759 * is required to set appropriate flowspec component type using function
760 * flow_builder_set_type(). This function should return 1 for successful
761 * adding, otherwise returns 0.
762 */
763 int
764 flow_builder_add_op_val(struct flow_builder *fb, byte op, u32 value)
765 {
766 if (!builder_add_prepare(fb))
767 return 0;
768
769 if (fb->this_type == fb->last_type)
770 {
771 /* Remove the end-bit from last operand-value pair of the component */
772 fb->data.data[fb->last_op_offset] &= 0x7f;
773 }
774 else
775 {
776 BUFFER_PUSH(fb->data) = fb->this_type;
777 }
778
779 fb->last_op_offset = fb->data.used;
780
781 /* Set the end-bit for operand-value pair of the component */
782 op |= 0x80;
783
784 if (value & 0xff00)
785 {
786 BUFFER_PUSH(fb->data) = op | 0x10;
787 put_u16(BUFFER_INC(fb->data, 2), value);
788 }
789 else
790 {
791 BUFFER_PUSH(fb->data) = op;
792 BUFFER_PUSH(fb->data) = (u8) value;
793 }
794
795 builder_add_finish(fb);
796 return 1;
797 }
798
799 /**
800 * flow_builder_add_val_mask - add value/bitmask pair
801 * @fb: flowspec builder instance
802 * @op: operator
803 * @value: value
804 * @mask: bitmask
805 *
806 * It is required to set appropriate flowspec component type using function
807 * flow_builder_set_type(). This function should return 1 for successful adding,
808 * otherwise returns 0.
809 */
810 int
811 flow_builder_add_val_mask(struct flow_builder *fb, byte op, u32 value, u32 mask)
812 {
813 u32 a = value & mask;
814 u32 b = ~value & mask;
815
816 if (a)
817 {
818 flow_builder_add_op_val(fb, op ^ 0x01, a);
819 op |= FLOW_OP_AND;
820 }
821
822 if (b)
823 flow_builder_add_op_val(fb, op ^ 0x02, b);
824
825 return 1;
826 }
827
828
829 /**
830 * flow_builder_set_type - set type of next flowspec component
831 * @fb: flowspec builder instance
832 * @type: flowspec component type
833 *
834 * This function sets type of next flowspec component. It is necessary to call
835 * this function before each changing of adding flowspec component.
836 */
837 void
838 flow_builder_set_type(struct flow_builder *fb, enum flow_type type)
839 {
840 fb->last_type = fb->this_type;
841 fb->this_type = type;
842 }
843
844 static void
845 builder_write_parts(struct flow_builder *fb, byte *buf)
846 {
847 for (int i = 1; i < FLOW_TYPE_MAX; i++)
848 {
849 if (fb->parts[i].length)
850 {
851 memcpy(buf, fb->data.data + fb->parts[i].offset, fb->parts[i].length);
852 buf += fb->parts[i].length;
853 }
854 }
855 }
856
857 /**
858 * flow_builder4_finalize - assemble final flowspec data structure &net_addr_flow4
859 * @fb: flowspec builder instance
860 * @lpool: linear memory pool
861 *
862 * This function returns final flowspec data structure &net_addr_flow4 allocated
863 * onto @lpool linear memory pool.
864 */
865 net_addr_flow4 *
866 flow_builder4_finalize(struct flow_builder *fb, linpool *lpool)
867 {
868 uint data_len = fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
869 net_addr_flow4 *f = lp_alloc(lpool, sizeof(struct net_addr_flow4) + data_len);
870
871 ip4_addr prefix = IP4_NONE;
872 uint pxlen = 0;
873
874 if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
875 {
876 byte *part = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset;
877 prefix = flow_read_ip4_part(part);
878 pxlen = part[1];
879 }
880 *f = NET_ADDR_FLOW4(prefix, pxlen, data_len);
881
882 builder_write_parts(fb, f->data + flow_write_length(f->data, fb->data.used));
883
884 return f;
885 }
886
887 /**
888 * flow_builder6_finalize - assemble final flowspec data structure &net_addr_flow6
889 * @fb: flowspec builder instance
890 * @lpool: linear memory pool for allocation of
891 *
892 * This function returns final flowspec data structure &net_addr_flow6 allocated
893 * onto @lpool linear memory pool.
894 */
895 net_addr_flow6 *
896 flow_builder6_finalize(struct flow_builder *fb, linpool *lpool)
897 {
898 uint data_len = fb->data.used + (fb->data.used < 0xf0 ? 1 : 2);
899 net_addr_flow6 *n = lp_alloc(lpool, sizeof(net_addr_flow6) + data_len);
900
901 ip6_addr prefix = IP6_NONE;
902 uint pxlen = 0;
903
904 if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
905 {
906 byte *part = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset;
907 prefix = flow_read_ip6_part(part);
908 pxlen = part[1];
909 }
910 *n = NET_ADDR_FLOW6(prefix, pxlen, data_len);
911
912 builder_write_parts(fb, n->data + flow_write_length(n->data, fb->data.used));
913
914 return n;
915 }
916
917 /**
918 * flow_builder_clear - flush flowspec builder instance for another flowspec creation
919 * @fb: flowspec builder instance
920 *
921 * This function flushes all data from builder but it maintains pre-allocated
922 * buffer space.
923 */
924 void
925 flow_builder_clear(struct flow_builder *fb)
926 {
927 BUFFER(byte) data;
928 BUFFER_FLUSH(fb->data);
929
930 BUFFER_SHALLOW_COPY(data, fb->data);
931 memset(fb, 0, sizeof(struct flow_builder));
932 BUFFER_SHALLOW_COPY(fb->data, data);
933 }
934
935
936 /*
937 * Net Formatting
938 */
939
940 /* Flowspec operators for [op, value]+ pairs */
941
942 static const char *
943 num_op_str(const byte *op)
944 {
945 switch (*op & 0x07)
946 {
947 case FLOW_OP_TRUE: return "true";
948 case FLOW_OP_EQ: return "=";
949 case FLOW_OP_GT: return ">";
950 case FLOW_OP_GEQ: return ">=";
951 case FLOW_OP_LT: return "<";
952 case FLOW_OP_LEQ: return "<=";
953 case FLOW_OP_NEQ: return "!=";
954 case FLOW_OP_FALSE: return "false";
955 }
956
957 return NULL;
958 }
959
960 static uint
961 get_value(const byte *val, u8 len)
962 {
963 switch (len)
964 {
965 case 1: return *val;
966 case 2: return get_u16(val);
967 case 4: return get_u32(val);
968 // No component may have length 8
969 // case 8: return get_u64(val);
970 }
971
972 return 0;
973 }
974
975 static const char *
976 fragment_val_str(u8 val)
977 {
978 switch (val)
979 {
980 case 1: return "dont_fragment";
981 case 2: return "is_fragment";
982 case 4: return "first_fragment";
983 case 8: return "last_fragment";
984 }
985 return "???";
986 }
987
988 static void
989 net_format_flow_ip(buffer *b, const byte *part, int ipv6)
990 {
991 uint pxlen = part[1];
992 if (ipv6)
993 {
994 uint pxoffset = part[2];
995 if (pxoffset)
996 buffer_print(b, "%I6/%u offset %u; ", flow_read_ip6_part(part), pxlen, pxoffset);
997 else
998 buffer_print(b, "%I6/%u; ", flow_read_ip6_part(part), pxlen);
999 }
1000 else
1001 {
1002 buffer_print(b, "%I4/%u; ", flow_read_ip4_part(part), pxlen);
1003 }
1004 }
1005
1006 static void
1007 net_format_flow_num(buffer *b, const byte *part)
1008 {
1009 const byte *last_op = NULL;
1010 const byte *op = part+1;
1011 uint val;
1012 uint len;
1013 uint first = 1;
1014
1015 while (1)
1016 {
1017 if (!first)
1018 {
1019 /* XXX: I don't like this so complicated if-tree */
1020 if (!isset_and(op) &&
1021 ((num_op( op) == FLOW_OP_EQ) || (num_op( op) == FLOW_OP_GEQ)) &&
1022 ((num_op(last_op) == FLOW_OP_EQ) || (num_op(last_op) == FLOW_OP_LEQ)))
1023 {
1024 b->pos--; /* Remove last char (it is a space) */
1025 buffer_puts(b, ",");
1026 }
1027 else
1028 {
1029 buffer_puts(b, isset_and(op) ? "&& " : "|| ");
1030 }
1031 }
1032 first = 0;
1033
1034 len = get_value_length(op);
1035 val = get_value(op+1, len);
1036
1037 if (!isset_end(op) && !isset_and(op) && isset_and(op+1+len) &&
1038 (num_op(op) == FLOW_OP_GEQ) && (num_op(op+1+len) == FLOW_OP_LEQ))
1039 {
1040 /* Display interval */
1041 buffer_print(b, "%u..", val);
1042 op += 1 + len;
1043 len = get_value_length(op);
1044 val = get_value(op+1, len);
1045 buffer_print(b, "%u", val);
1046 }
1047 else if (num_op(op) == FLOW_OP_EQ)
1048 {
1049 buffer_print(b, "%u", val);
1050 }
1051 else
1052 {
1053 buffer_print(b, "%s %u", num_op_str(op), val);
1054 }
1055
1056 if (isset_end(op))
1057 {
1058 buffer_puts(b, "; ");
1059 break;
1060 }
1061 else
1062 {
1063 buffer_puts(b, " ");
1064 }
1065
1066 last_op = op;
1067 op += 1 + len;
1068 }
1069 }
1070
1071 static void
1072 net_format_flow_bitmask(buffer *b, const byte *part)
1073 {
1074 const byte *op = part+1;
1075 uint val;
1076 uint len;
1077 uint first = 1;
1078
1079 while (1)
1080 {
1081 if (!first)
1082 {
1083 if (isset_and(op))
1084 {
1085 b->pos--; /* Remove last char (it is a space) */
1086 buffer_puts(b, ",");
1087 }
1088 else
1089 {
1090 buffer_puts(b, "|| ");
1091 }
1092 }
1093 first = 0;
1094
1095 len = get_value_length(op);
1096 val = get_value(op+1, len);
1097
1098 /*
1099 * Not Match Show
1100 * ------------------
1101 * 0 0 !0/B
1102 * 0 1 B/B
1103 * 1 0 0/B
1104 * 1 1 !B/B
1105 */
1106
1107 if ((*op & 0x3) == 0x3 || (*op & 0x3) == 0)
1108 buffer_puts(b, "!");
1109
1110 if (*part == FLOW_TYPE_FRAGMENT && (val == 1 || val == 2 || val == 4 || val == 8))
1111 buffer_print(b, "%s%s", ((*op & 0x1) ? "" : "!"), fragment_val_str(val));
1112 else
1113 buffer_print(b, "0x%x/0x%x", ((*op & 0x1) ? val : 0), val);
1114
1115 if (isset_end(op))
1116 {
1117 buffer_puts(b, "; ");
1118 break;
1119 }
1120 else
1121 {
1122 buffer_puts(b, " ");
1123 }
1124
1125 op += 1 + len;
1126 }
1127 }
1128
1129 static uint
1130 net_format_flow(char *buf, uint blen, const byte *data, uint dlen, int ipv6)
1131 {
1132 buffer b = {
1133 .start = buf,
1134 .pos = buf,
1135 .end = buf + blen,
1136 };
1137
1138 const byte *part = flow_first_part(data);
1139 *buf = 0;
1140
1141 if (ipv6)
1142 buffer_puts(&b, "flow6 { ");
1143 else
1144 buffer_puts(&b, "flow4 { ");
1145
1146 while (part)
1147 {
1148 buffer_print(&b, "%s ", flow_type_str(*part, ipv6));
1149
1150 switch (*part)
1151 {
1152 case FLOW_TYPE_DST_PREFIX:
1153 case FLOW_TYPE_SRC_PREFIX:
1154 net_format_flow_ip(&b, part, ipv6);
1155 break;
1156 case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
1157 case FLOW_TYPE_PORT:
1158 case FLOW_TYPE_DST_PORT:
1159 case FLOW_TYPE_SRC_PORT:
1160 case FLOW_TYPE_ICMP_TYPE:
1161 case FLOW_TYPE_ICMP_CODE:
1162 case FLOW_TYPE_PACKET_LENGTH:
1163 case FLOW_TYPE_DSCP:
1164 net_format_flow_num(&b, part);
1165 break;
1166 case FLOW_TYPE_TCP_FLAGS:
1167 case FLOW_TYPE_FRAGMENT:
1168 case FLOW_TYPE_LABEL:
1169 net_format_flow_bitmask(&b, part);
1170 break;
1171 }
1172
1173 part = flow_next_part(part, data+dlen, ipv6);
1174 }
1175
1176 buffer_puts(&b, "}");
1177
1178 if (b.pos == b.end)
1179 {
1180 b.pos = b.start + MIN(blen - 6, strlen(b.start));
1181 buffer_puts(&b, " ...}");
1182 }
1183
1184 return b.pos - b.start;
1185 }
1186
1187 /**
1188 * flow4_net_format - stringify flowspec data structure &net_addr_flow4
1189 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1190 * @blen: free allocated space in @buf
1191 * @f: flowspec data structure &net_addr_flow4 for stringify
1192 *
1193 * This function writes stringified @f into @buf. The function returns number
1194 * of written chars. If final string is too large, the string will ends the with
1195 * ' ...}' sequence and zero-terminator.
1196 */
1197 uint
1198 flow4_net_format(char *buf, uint blen, const net_addr_flow4 *f)
1199 {
1200 return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow4), 0);
1201 }
1202
1203 /**
1204 * flow6_net_format - stringify flowspec data structure &net_addr_flow6
1205 * @buf: pre-allocated buffer for writing a stringify net address flowspec
1206 * @blen: free allocated space in @buf
1207 * @f: flowspec data structure &net_addr_flow4 for stringify
1208 *
1209 * This function writes stringified @f into @buf. The function returns number
1210 * of written chars. If final string is too large, the string will ends the with
1211 * ' ...}' sequence and zero-terminator.
1212 */
1213 uint
1214 flow6_net_format(char *buf, uint blen, const net_addr_flow6 *f)
1215 {
1216 return net_format_flow(buf, blen, f->data, f->length - sizeof(net_addr_flow6), 1);
1217 }