Annotation of embedaddon/bird2/lib/flowspec.c, revision 1.1.1.1
1.1 misho 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: /*
117: * Flowspec iterators
118: */
119:
120: static inline u8 num_op(const byte *op) { return (*op & 0x07); }
121: static inline int isset_and(const byte *op) { return ((*op & 0x40) == 0x40); }
122: static inline int isset_end(const byte *op) { return ((*op & 0x80) == 0x80); }
123:
124: static const byte *
125: flow_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: */
144: inline const byte *
145: flow4_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: */
157: inline const byte *
158: flow6_first_part(const net_addr_flow6 *f)
159: {
160: return f ? flow_first_part(f->data) : NULL;
161: }
162:
163: static const byte *
164: flow_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: */
226: inline const byte *
227: flow4_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: */
241: inline const byte *
242: flow6_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:
252: static 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",
262: [FLOW_ST_DEST_PREFIX_REQUIRED] = "Destination prefix is missing",
263: [FLOW_ST_INVALID_TCP_FLAGS] = "TCP flags exceeding 0xfff",
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: */
273: const char *
274: flow_validated_state_str(enum flow_validated_state code)
275: {
276: return flow_validated_state_str_[code];
277: }
278:
279: static 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:
294: static 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:
310: static u8
311: flow_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: */
327: void
328: flow_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:
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);
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: */
355: void
356: flow_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:
371: static enum flow_validated_state
372: flow_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:
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;
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:
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: */
512: inline enum flow_validated_state
513: flow4_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: */
527: inline enum flow_validated_state
528: flow6_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: */
540: void
541: flow4_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: */
556: void
557: flow6_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: */
576: struct flow_builder *
577: flow_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:
584: static int
585: is_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:
608: static int
609: builder_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:
627: static void
628: builder_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:
634: static void
635: push_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: */
648: int
649: flow_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: */
673: int
674: flow_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: */
701: int
702: flow_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: */
748: int
749: flow_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);
757: op |= FLOW_OP_AND;
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: */
775: void
776: flow_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:
782: static ip4_addr
783: flow_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:
790: static ip6_addr
791: flow_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:
802: static void
803: builder_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: */
823: net_addr_flow4 *
824: flow_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: */
853: net_addr_flow6 *
854: flow_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: */
883: void
884: flow_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 */
900:
901: static const char *
902: num_op_str(const byte *op)
903: {
904: switch (*op & 0x07)
905: {
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";
914: }
915:
916: return NULL;
917: }
918:
919: static uint
920: get_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);
927: // No component may have length 8
928: // case 8: return get_u64(val);
929: }
930:
931: return 0;
932: }
933:
934: static const char *
935: fragment_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:
947: static void
948: net_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:
965: static void
966: net_format_flow_num(buffer *b, const byte *part)
967: {
968: const byte *last_op = NULL;
969: const byte *op = part+1;
970: uint val;
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) &&
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)))
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) &&
997: (num_op(op) == FLOW_OP_GEQ) && (num_op(op+1+len) == FLOW_OP_LEQ))
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: }
1006: else if (num_op(op) == FLOW_OP_EQ)
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:
1030: static void
1031: net_format_flow_bitmask(buffer *b, const byte *part)
1032: {
1033: const byte *op = part+1;
1034: uint val;
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:
1088: static uint
1089: net_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:
1113: net_format_flow_ip(&b, part, ipv6);
1114: break;
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:
1121: case FLOW_TYPE_PACKET_LENGTH:
1122: case FLOW_TYPE_DSCP:
1123: net_format_flow_num(&b, part);
1124: break;
1125: case FLOW_TYPE_TCP_FLAGS:
1126: case FLOW_TYPE_FRAGMENT:
1127: case FLOW_TYPE_LABEL:
1128: net_format_flow_bitmask(&b, part);
1129: break;
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: */
1156: uint
1157: flow4_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: */
1172: uint
1173: flow6_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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>