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