File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bird2 / lib / flowspec.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 16:03:56 2019 UTC (4 years, 9 months ago) by misho
Branches: bird2, MAIN
CVS tags: v2_0_7p0, HEAD
bird2 ver 2.0.7

    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>