case FLOW_TYPE_SRC_PREFIX:
{
uint pxlen = *pos++;
- uint bytes = BYTES(pxlen);
- if (ipv6)
- {
- uint offset = *pos++ / 8;
- pos += bytes - offset;
- }
- else
- {
- pos += bytes;
- }
+ uint offset = ipv6 ? *pos++ : 0;
+ pos += BYTES(pxlen - offset);
break;
}
[FLOW_ST_EXCEED_MAX_PREFIX_OFFSET] = "Exceed maximal prefix offset",
[FLOW_ST_EXCEED_MAX_VALUE_LENGTH] = "Exceed maximal value length",
[FLOW_ST_BAD_TYPE_ORDER] = "Bad component order",
- [FLOW_ST_AND_BIT_SHOULD_BE_UNSET] = "The AND-bit should be unset",
- [FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED] = "The Zero-bit should be unset",
- [FLOW_ST_DEST_PREFIX_REQUIRED] = "Destination prefix is missing",
- [FLOW_ST_INVALID_TCP_FLAGS] = "TCP flags exceeding 0xfff",
- [FLOW_ST_CANNOT_USE_DONT_FRAGMENT] = "Cannot use Don't fragment flag in IPv6 flow"
+ [FLOW_ST_NONZERO_PADDING] = "Nonzero prefix padding",
+ [FLOW_ST_FIRST_AND_BIT_SET] = "The first AND-bit is set",
+ [FLOW_ST_ZERO_BIT_SET] = "Zero-bit is set",
+ [FLOW_ST_INVALID_TCP_FLAGS] = "Invalid TCP flags bitmask operand",
+ [FLOW_ST_INVALID_FRAGMENT] = "Invalid fragment bitmask operand",
};
/**
return flow_validated_state_str_[code];
}
-static const u8 flow4_max_value_length[] = {
- [FLOW_TYPE_DST_PREFIX] = 0,
- [FLOW_TYPE_SRC_PREFIX] = 0,
- [FLOW_TYPE_IP_PROTOCOL] = 1,
- [FLOW_TYPE_PORT] = 2,
- [FLOW_TYPE_DST_PORT] = 2,
- [FLOW_TYPE_SRC_PORT] = 2,
- [FLOW_TYPE_ICMP_TYPE] = 1,
- [FLOW_TYPE_ICMP_CODE] = 1,
+/* Maximum length of value fields, as mandated by RFC 8955 */
+static const u8 flow_max_value_length[FLOW_TYPE_MAX] = {
[FLOW_TYPE_TCP_FLAGS] = 2,
- [FLOW_TYPE_PACKET_LENGTH] = 2,
[FLOW_TYPE_DSCP] = 1,
- [FLOW_TYPE_FRAGMENT] = 1 /* XXX */
+ [FLOW_TYPE_FRAGMENT] = 1,
};
-static const u8 flow6_max_value_length[] = {
- [FLOW_TYPE_DST_PREFIX] = 0,
- [FLOW_TYPE_SRC_PREFIX] = 0,
- [FLOW_TYPE_NEXT_HEADER] = 1,
+/* Maximum valid numeric values (in bytes), semantically */
+static const u8 flow_max_valid_value[FLOW_TYPE_MAX] = {
+ [FLOW_TYPE_IP_PROTOCOL] = 1,
[FLOW_TYPE_PORT] = 2,
[FLOW_TYPE_DST_PORT] = 2,
[FLOW_TYPE_SRC_PORT] = 2,
[FLOW_TYPE_ICMP_TYPE] = 1,
[FLOW_TYPE_ICMP_CODE] = 1,
- [FLOW_TYPE_TCP_FLAGS] = 2,
[FLOW_TYPE_PACKET_LENGTH] = 2,
[FLOW_TYPE_DSCP] = 1,
- [FLOW_TYPE_FRAGMENT] = 1, /* XXX */
- [FLOW_TYPE_LABEL] = 4
+ [FLOW_TYPE_LABEL] = 4,
};
-static u8
-flow_max_value_length(enum flow_type type, int ipv6)
-{
- return ipv6 ? flow6_max_value_length[type] : flow4_max_value_length[type];
-}
-
/**
- * flow_check_cf_bmk_values - check value/bitmask part of flowspec component
+ * flow_check_cf_bitmask_arg - check value/bitmask part of flowspec component
* @fb: flow builder instance
* @neg: negation operand
* @val: value from value/mask pair
* to failing of validation.
*/
void
-flow_check_cf_bmk_values(struct flow_builder *fb, u8 neg, u32 val, u32 mask)
+flow_check_cf_bitmask_arg(struct flow_builder *fb, u8 neg, u32 val, u32 mask)
{
- flow_check_cf_value_length(fb, val);
- flow_check_cf_value_length(fb, mask);
-
if (neg && !(val == 0 || val == mask))
cf_error("For negation, value must be zero or bitmask");
- if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & 0xf000))
+ if ((fb->this_type == FLOW_TYPE_TCP_FLAGS) && (mask & ~0xfff))
cf_error("Invalid mask 0x%x, must not exceed 0xfff", mask);
- if ((fb->this_type == FLOW_TYPE_FRAGMENT) && fb->ipv6 && (mask & 0x01))
- cf_error("Invalid mask 0x%x, bit 0 must be 0", mask);
+ u32 valid = fb->ipv6 ? 0x0e : 0x0f;
+ if ((fb->this_type == FLOW_TYPE_FRAGMENT) && (mask & ~valid))
+ cf_error("Invalid mask 0x%x, must not exceed 0x%x", mask, valid);
if (val & ~mask)
cf_error("Value 0x%x outside bitmask 0x%x", val, mask);
}
/**
- * flow_check_cf_value_length - check value by flowspec component type
+ * flow_check_cf_numeric_arg - check numeric argument of flowspec component
* @fb: flow builder instance
* @val: value
*
- * This function checks if the value is in range of component's type support.
- * If some problem will appear, the function calls cf_error() function with
- * a textual description of reason to failing of validation.
+ * This function checks the value of numeric argument to see whether it is in
+ * the range of component's type. If some problem will appear, the function
+ * calls cf_error() function with a textual description of reason to failing of
+ * validation.
*/
void
-flow_check_cf_value_length(struct flow_builder *fb, u32 val)
+flow_check_cf_numeric_arg(struct flow_builder *fb, uint val)
{
enum flow_type t = fb->this_type;
- u8 max = flow_max_value_length(t, fb->ipv6);
+ uint max = flow_max_valid_value[t];
if (t == FLOW_TYPE_DSCP && val > 0x3f)
cf_error("%s value %u out of range (0-63)", flow_type_str(t, fb->ipv6), val);
cf_error("%s value %u out of range (0-65535)", flow_type_str(t, fb->ipv6), val);
}
+/* Bitmask of padding bits in last byte of prefix */
+static inline u8
+flow_padding(uint n)
+{
+ ASSUME(n % 8 != 0);
+ return (1 << (8 - n % 8)) - 1;
+}
+
static enum flow_validated_state
-flow_validate(const byte *nlri, uint len, int ipv6)
+flow_decode(byte *nlri, uint length, bool ipv6)
{
enum flow_type type = 0;
- const byte *pos = nlri;
- const byte *end = nlri + len;
+ byte *pos = nlri;
+ byte *end = nlri + length;
while (pos < end)
{
/* Check increasing type ordering */
if (*pos <= type)
return FLOW_ST_BAD_TYPE_ORDER;
+
type = *pos++;
switch (type)
case FLOW_TYPE_DST_PREFIX:
case FLOW_TYPE_SRC_PREFIX:
{
- uint pxlen = *pos++;
- if (pxlen > (ipv6 ? IP6_MAX_PREFIX_LENGTH : IP4_MAX_PREFIX_LENGTH))
- return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
+ uint pxlen, offset = 0;
+
+ if (!ipv6)
+ {
+ if (pos + 1 > end)
+ return FLOW_ST_NOT_COMPLETE;
- uint bytes = BYTES(pxlen);
- if (ipv6)
+ pxlen = *pos++;
+
+ if (pxlen > IP4_MAX_PREFIX_LENGTH)
+ return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
+ }
+ else
{
- uint pxoffset = *pos++;
- if (pxoffset > IP6_MAX_PREFIX_LENGTH || pxoffset > pxlen)
- return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
- bytes = BYTES(pxlen - pxoffset);
+ if (pos + 2 > end)
+ return FLOW_ST_NOT_COMPLETE;
+
+ pxlen = *pos++;
+ offset = *pos++;
+
+ if (pxlen > IP6_MAX_PREFIX_LENGTH)
+ return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
+
+ if (offset > pxlen)
+ return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
}
- pos += bytes;
+
+ uint bits = pxlen - offset;
+ pos += BYTES(bits);
+
+ if (pos > end)
+ return FLOW_ST_NOT_COMPLETE;
+
+ /* Padding bits in the last byte MUST be 0 */
+ if (bits % 8)
+ pos[-1] &= ~flow_padding(bits);
break;
}
if (!ipv6)
return FLOW_ST_UNKNOWN_COMPONENT;
/* fall through */
+
case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
case FLOW_TYPE_PORT:
case FLOW_TYPE_DST_PORT:
case FLOW_TYPE_DSCP:
case FLOW_TYPE_FRAGMENT:
{
- uint last = 0;
- uint first = 1;
-
+ /*
+ * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ * +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
+ * | e | a | len | 0 |lt |gt |eq | | e | a | len | 0 | 0 |not| m |
+ * +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
+ *
+ * Numeric operator Bitmask operator
+ */
+
+ bool first = true;
+ bool last = false;
while (!last)
{
- /*
- * 0 1 2 3 4 5 6 7
- * +---+---+---+---+---+---+---+---+
- * | e | a | len | 0 |lt |gt |eq |
- * +---+---+---+---+---+---+---+---+
- *
- * Numeric operator
- */
+ if (pos + 1 > end)
+ return FLOW_ST_NOT_COMPLETE;
- last = isset_end(pos);
+ uint len = get_value_length(pos);
- /* The AND bit should in the first operator byte of a sequence */
- if (first && isset_and(pos))
- return FLOW_ST_AND_BIT_SHOULD_BE_UNSET;
+ /* Some component values MUST be encoded with limited length */
+ uint maxlen = flow_max_value_length[type];
+ if (maxlen && (len > maxlen))
+ return FLOW_ST_EXCEED_MAX_VALUE_LENGTH;
- /* This bit should be zero */
- if (*pos & 0x08)
- return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
+ if (pos + 1 + len > end)
+ return FLOW_ST_NOT_COMPLETE;
- if (type == FLOW_TYPE_TCP_FLAGS || type == FLOW_TYPE_FRAGMENT)
- {
- /*
- * 0 1 2 3 4 5 6 7
- * +---+---+---+---+---+---+---+---+
- * | e | a | len | 0 | 0 |not| m |
- * +---+---+---+---+---+---+---+---+
- *
- * Bitmask operand
- */
- if (*pos & 0x04)
- return FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED;
- }
+ /* In first operator of sequence, AND bit ... MUST be ignored during decoding */
+ if (first)
+ pos[0] &= ~0x40;
- /* Value length of operator */
- uint len = get_value_length(pos);
- if (len > flow_max_value_length(type, ipv6))
- return FLOW_ST_EXCEED_MAX_VALUE_LENGTH;
+ /* Zero field MUST be set to 0 on encoding and MUST be ignored during decoding */
+ pos[0] &= ~0x08;
+
+ /* Bitmask operator has additional zero field */
+ if (type == FLOW_TYPE_TCP_FLAGS || type == FLOW_TYPE_FRAGMENT)
+ pos[0] &= ~0x04;
- /* TCP Flags component must not check highest nibble (just 12 valid bits) */
- if ((type == FLOW_TYPE_TCP_FLAGS) && (len == 2) && (pos[1] & 0xf0))
- return FLOW_ST_INVALID_TCP_FLAGS;
+ /* Zero fields in highest nibble of TCP Flags bitmask operand */
+ if ((type == FLOW_TYPE_TCP_FLAGS) && (len == 2))
+ pos[1] &= ~0xf0;
- /* Bit-7 must be 0 [draft-ietf-idr-flow-spec-v6] */
- if ((type == FLOW_TYPE_FRAGMENT) && ipv6 && (pos[1] & 0x01))
- return FLOW_ST_CANNOT_USE_DONT_FRAGMENT;
- /* XXX: Could be a fragment component encoded in 2-bytes? */
+ /* Zero fields in fragment bitmask operand */
+ if ((type == FLOW_TYPE_FRAGMENT) && (len == 1))
+ pos[1] &= ipv6 ? ~0xf1 : ~0xf0;
+ /* Move to next operator */
+ first = false;
+ last = isset_end(pos);
pos += 1+len;
+ }
+ break;
+ }
+
+ default:
+ return FLOW_ST_UNKNOWN_COMPONENT;
+ }
+ }
+
+ if (pos != end)
+ return FLOW_ST_NOT_COMPLETE;
+
+ return FLOW_ST_VALID;
+}
+
+/**
+ * flow4_decode - decode incoming BGP IPv4 flowspec data stream
+ * @nlri: flowspec data stream without length header
+ * @len: length of @nlri
+ *
+ * This function checks syntatic correctness of binary flowspec. It returns
+ * %FLOW_ST_VALID, or some other %FLOW_ST_xxx state if the NLRI is malformed.
+ * If the NLRI is valid but not normalized (e.g. some zero bits are set), the
+ * flow4_decode() modify the datastream to normalize it.
+ */
+inline enum flow_validated_state
+flow4_decode(byte *nlri, uint len)
+{
+ return flow_decode(nlri, len, false);
+}
+
+/**
+ * flow6_decode - decode incoming BGP IPv6 flowspec data stream
+ * @nlri: flowspec data stream without length header
+ * @len: length of @nlri
+ *
+ * This function checks syntatic correctness of binary flowspec. It returns
+ * %FLOW_ST_VALID, or some other %FLOW_ST_xxx state if the NLRI is malformed.
+ * If the NLRI is valid but not normalized (e.g. some zero bits are set), the
+ * flow6_decode() modify the datastream to normalize it.
+ */
+inline enum flow_validated_state
+flow6_decode(byte *nlri, uint len)
+{
+ return flow_decode(nlri, len, true);
+}
+
+static enum flow_validated_state
+flow_validate(const byte *nlri, uint len, bool ipv6)
+{
+ enum flow_type type = 0;
+ const byte *pos = nlri;
+ const byte *end = nlri + len;
+
+ while (pos < end)
+ {
+ /* Check increasing type ordering */
+ if (*pos <= type)
+ return FLOW_ST_BAD_TYPE_ORDER;
+
+ type = *pos++;
+
+ switch (type)
+ {
+ case FLOW_TYPE_DST_PREFIX:
+ case FLOW_TYPE_SRC_PREFIX:
+ {
+ uint pxlen, offset = 0;
- if (pos > end && !last)
+ if (!ipv6)
+ {
+ if (pos + 1 > end)
return FLOW_ST_NOT_COMPLETE;
- if (pos > (end+1))
+ pxlen = *pos++;
+
+ if (pxlen > IP4_MAX_PREFIX_LENGTH)
+ return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
+ }
+ else
+ {
+ if (pos + 2 > end)
return FLOW_ST_NOT_COMPLETE;
- first = 0;
+ pxlen = *pos++;
+ offset = *pos++;
+
+ if (pxlen > IP6_MAX_PREFIX_LENGTH)
+ return FLOW_ST_EXCEED_MAX_PREFIX_LENGTH;
+
+ if (offset > pxlen)
+ return FLOW_ST_EXCEED_MAX_PREFIX_OFFSET;
}
+
+ uint bits = pxlen - offset;
+ pos += BYTES(bits);
+
+ if (pos > end)
+ return FLOW_ST_NOT_COMPLETE;
+
+ /* Padding bits in the last byte MUST be 0 */
+ if (bits % 8)
+ if (pos[-1] & flow_padding(bits))
+ return FLOW_ST_NONZERO_PADDING;
+
break;
}
+
+ case FLOW_TYPE_LABEL:
+ if (!ipv6)
+ return FLOW_ST_UNKNOWN_COMPONENT;
+ /* fall through */
+
+ case FLOW_TYPE_IP_PROTOCOL: /* == FLOW_TYPE_NEXT_HEADER */
+ case FLOW_TYPE_PORT:
+ case FLOW_TYPE_DST_PORT:
+ case FLOW_TYPE_SRC_PORT:
+ case FLOW_TYPE_ICMP_TYPE:
+ case FLOW_TYPE_ICMP_CODE:
+ case FLOW_TYPE_TCP_FLAGS:
+ case FLOW_TYPE_PACKET_LENGTH:
+ case FLOW_TYPE_DSCP:
+ case FLOW_TYPE_FRAGMENT:
+ {
+ /*
+ * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+ * +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
+ * | e | a | len | 0 |lt |gt |eq | | e | a | len | 0 | 0 |not| m |
+ * +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
+ *
+ * Numeric operator Bitmask operator
+ */
+
+ bool first = true;
+ bool last = false;
+ while (!last)
+ {
+ if (pos + 1 > end)
+ return FLOW_ST_NOT_COMPLETE;
+
+ uint len = get_value_length(pos);
+
+ /* Some component values MUST be encoded with limited length */
+ uint maxlen = flow_max_value_length[type];
+ if (maxlen && (len > maxlen))
+ return FLOW_ST_EXCEED_MAX_VALUE_LENGTH;
+
+ if (pos + 1 + len > end)
+ return FLOW_ST_NOT_COMPLETE;
+
+ /* In first operator of sequence, AND bit ... MUST be ignored during decoding */
+ if (first && isset_and(pos))
+ return FLOW_ST_FIRST_AND_BIT_SET;
+
+ /* Zero field MUST be set to 0 on encoding and MUST be ignored during decoding */
+ if (pos[0] & 0x08)
+ return FLOW_ST_ZERO_BIT_SET;
+
+ /* Bitmask operator has additional zero field */
+ if (type == FLOW_TYPE_TCP_FLAGS || type == FLOW_TYPE_FRAGMENT)
+ if (pos[0] & 0x04)
+ return FLOW_ST_ZERO_BIT_SET;
+
+ /* Zero fields in highest nibble of TCP Flags bitmask operand */
+ if ((type == FLOW_TYPE_TCP_FLAGS) && (len == 2))
+ if (pos[1] & 0xf0)
+ return FLOW_ST_INVALID_TCP_FLAGS;
+
+ /* Zero fields in fragment bitmask operand */
+ if ((type == FLOW_TYPE_FRAGMENT) && (len == 1))
+ if (pos[1] & (ipv6 ? 0xf1 : 0xf0))
+ return FLOW_ST_INVALID_FRAGMENT;
+
+ /* Move to next operator */
+ first = false;
+ last = isset_end(pos);
+ pos += 1+len;
+ }
+ break;
+ }
+
default:
return FLOW_ST_UNKNOWN_COMPONENT;
}
/**
* flow4_validate - check untrustworthy IPv4 flowspec data stream
- * @nlri: flowspec data stream without compressed encoded length value
+ * @nlri: flowspec data stream without length header
* @len: length of @nlri
*
- * This function checks meaningfulness of binary flowspec. It should return
- * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
- * returns some other %FLOW_ST_xxx state.
+ * This function checks syntactic correctness of binary flowspec. It returns
+ * %FLOW_ST_VALID, or some other %FLOW_ST_xxx state if the NLRI is malformed
+ * or non-normalized.
*/
inline enum flow_validated_state
flow4_validate(const byte *nlri, uint len)
{
- return flow_validate(nlri, len, 0);
+ return flow_validate(nlri, len, false);
}
/**
* flow6_validate - check untrustworthy IPv6 flowspec data stream
- * @nlri: flowspec binary stream without encoded length value
+ * @nlri: flowspec binary stream without length header
* @len: length of @nlri
*
- * This function checks meaningfulness of binary flowspec. It should return
- * %FLOW_ST_VALID or %FLOW_ST_UNKNOWN_COMPONENT. If some problem appears, it
- * returns some other %FLOW_ST_xxx state.
+ * This function checks syntactic correctness of binary flowspec. It returns
+ * %FLOW_ST_VALID, or some other %FLOW_ST_xxx state if the NLRI is malformed
+ * or non-normalized.
*/
inline enum flow_validated_state
flow6_validate(const byte *nlri, uint len)
{
- return flow_validate(nlri, len, 1);
+ return flow_validate(nlri, len, true);
}
/**
/* Set the end-bit for operand-value pair of the component */
op |= 0x80;
- if (value & 0xff00)
+ /* Label component values SHOULD be encoded as 4-octet quantities */
+ if ((value > 0xffff) || (fb->this_type == FLOW_TYPE_LABEL))
+ {
+ BUFFER_PUSH(fb->data) = op | 0x20;
+ put_u32(BUFFER_INC(fb->data, 4), value);
+ }
+ else if (value > 0xff)
{
BUFFER_PUSH(fb->data) = op | 0x10;
put_u16(BUFFER_INC(fb->data, 2), value);
FLOW_TYPE_DST_PREFIX, 33, 5, 6, 7, 8, 9
})
),
+ TS(
+ FLOW_ST_EXCEED_MAX_VALUE_LENGTH,
+ "DSCP of length 2",
+ ((byte []) {
+ FLOW_TYPE_DSCP, 0x91, 00, 63,
+ })
+ ),
TS(
FLOW_ST_BAD_TYPE_ORDER,
"Bad flowspec component type order",
})
),
TS(
- FLOW_ST_AND_BIT_SHOULD_BE_UNSET,
+ FLOW_ST_UNKNOWN_COMPONENT,
+ "Unknown component of type number 14",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
+ 14 /*something new*/, 0x80, 0x55,
+ })
+ ),
+ TS(
+ FLOW_ST_UNKNOWN_COMPONENT,
+ "Label component in IPv4",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_LABEL, 0xa0, 0, 0, 0, 0x55,
+ })
+ ),
+ TS(
+ FLOW_ST_NONZERO_PADDING,
+ "Non-zero padding in prefix",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 20, 5, 6, 7,
+ })
+ ),
+ TS(
+ FLOW_ST_FIRST_AND_BIT_SET,
"The first numeric operator has set the AND bit",
((byte []) {
FLOW_TYPE_PORT, 0x43, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
})
),
TS(
- FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED,
- "Set zero bit in operand to one",
+ FLOW_ST_ZERO_BIT_SET,
+ "Set zero bit in operator to one (0x08)",
((byte []) {
FLOW_TYPE_IP_PROTOCOL, 0x89, 0x06,
})
),
TS(
- FLOW_ST_UNKNOWN_COMPONENT,
- "Unknown component of type number 13",
+ FLOW_ST_ZERO_BIT_SET,
+ "Set zero bit in operator to one (0x04)",
((byte []) {
- FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
- FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
- 13 /*something new*/, 0x80, 0x55,
+ FLOW_TYPE_FRAGMENT, 0x84, 0x03,
})
),
+ TS(
+ FLOW_ST_INVALID_TCP_FLAGS,
+ "Set zero bit in operand to one (TCP flags)",
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x91, 0xff, 0x3a,
+ })
+ ),
+ TS(
+ FLOW_ST_INVALID_FRAGMENT,
+ "Set zero bit in operand to one (fragment)",
+ ((byte []) {
+ FLOW_TYPE_FRAGMENT, 0x81, 0xff,
+ })
+ ),
+
};
#undef TS
enum flow_validated_state res;
byte nlri1[] = {
- FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0x98,
+ FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0xc0,
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
FLOW_TYPE_DST_PREFIX, 48, 64, 0x40, 0x12, 0x34
})
),
+ TS(
+ FLOW_ST_EXCEED_MAX_VALUE_LENGTH,
+ "Fragment of length 2",
+ ((byte []) {
+ FLOW_TYPE_FRAGMENT, 0x91, 00, 0x0f,
+ })
+ ),
TS(
FLOW_ST_BAD_TYPE_ORDER,
"Bad flowspec component type order",
FLOW_ST_BAD_TYPE_ORDER,
"Doubled destination prefix component",
((byte []) {
- FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0x98,
- FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0x98,
+ FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0xc0,
+ FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0xc0,
})
),
TS(
- FLOW_ST_AND_BIT_SHOULD_BE_UNSET,
+ FLOW_ST_UNKNOWN_COMPONENT,
+ "Unknown component of type number 14",
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
+ 14 /*something new*/, 0x80, 0x55,
+ })
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "Label component is well-known in IPv6",
+ ((byte []) {
+ FLOW_TYPE_LABEL, 0xa0, 0, 0, 0, 0x55,
+ })
+ ),
+ TS(
+ FLOW_ST_NONZERO_PADDING,
+ "Non-zero padding in prefix",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 44, 16, 0x40, 0x12, 0x34, 0x56,
+ })
+ ),
+ TS(
+ FLOW_ST_FIRST_AND_BIT_SET,
"The first numeric operator has set the AND bit",
((byte []) {
FLOW_TYPE_PORT, 0x43, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90
})
),
TS(
- FLOW_ST_ZERO_BIT_SHOULD_BE_UNSED,
- "Set zero bit in operand to one",
+ FLOW_ST_ZERO_BIT_SET,
+ "Set zero bit in operator to one (0x08)",
((byte []) {
FLOW_TYPE_NEXT_HEADER, 0x89, 0x06
})
),
+ TS(
+ FLOW_ST_ZERO_BIT_SET,
+ "Set zero bit in operator to one (0x04)",
+ ((byte []) {
+ FLOW_TYPE_FRAGMENT, 0x84, 0x03,
+ })
+ ),
+ TS(
+ FLOW_ST_INVALID_TCP_FLAGS,
+ "Set zero bit in operand to one (TCP flags)",
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x91, 0xff, 0x3a,
+ })
+ ),
+ TS(
+ FLOW_ST_INVALID_FRAGMENT,
+ "Set zero bit in operand to one (fragment)",
+ ((byte []) {
+ FLOW_TYPE_FRAGMENT, 0x81, 0xff,
+ })
+ ),
+ };
+#undef TS
+
+ for (uint tcase = 0; tcase < ARRAY_SIZE(tset); tcase++)
+ {
+ res = flow6_validate(tset[tcase].nlri, tset[tcase].size);
+ bt_assert_msg(res == tset[tcase].expect, "Assertion (%s == %s) %s", flow_validated_state_str(res), flow_validated_state_str(tset[tcase].expect), tset[tcase].description);
+ }
+
+ return 1;
+}
+
+static int
+t_decoding4(void)
+{
+ enum flow_validated_state res;
+
+ byte nlri1[] = {
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_SRC_PREFIX, 32, 10, 11, 12, 13,
+ FLOW_TYPE_IP_PROTOCOL, 0x81, 0x06,
+ FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
+ };
+
+ /* Empty NLRI */
+ res = flow4_decode(nlri1, 0);
+ bt_assert(res == FLOW_ST_VALID);
+
+ /* Valid / Not Complete testing */
+ uint valid_sizes[] = {5, 11, 14, 22, 25, 0};
+ uint valid_idx = 0;
+ for (uint size = 1; size <= sizeof(nlri1); size++)
+ {
+ res = flow4_decode(nlri1, size);
+ bt_debug("size %u, result: %s\n", size, flow_validated_state_str(res));
+ if (size == valid_sizes[valid_idx])
+ {
+ valid_idx++;
+ bt_assert(res == FLOW_ST_VALID);
+ }
+ else
+ {
+ bt_assert(res == FLOW_ST_NOT_COMPLETE);
+ }
+ }
+
+ /* Misc err tests */
+
+ struct tset {
+ enum flow_validated_state expect;
+ char *description;
+ u16 size;
+ byte *nlri;
+ byte *result;
+ };
+
+#define TS(type, msg, data, result) ((struct tset) {type, msg, sizeof(data), (data), (result)})
+ struct tset tset[] = {
+ TS(
+ FLOW_ST_EXCEED_MAX_PREFIX_LENGTH,
+ "33-length IPv4 prefix",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 33, 5, 6, 7, 8, 9
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_EXCEED_MAX_VALUE_LENGTH,
+ "DSCP of length 2",
+ ((byte []) {
+ FLOW_TYPE_DSCP, 0x91, 00, 63,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_BAD_TYPE_ORDER,
+ "Bad flowspec component type order",
+ ((byte []) {
+ FLOW_TYPE_SRC_PREFIX, 32, 10, 11, 12, 13,
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_BAD_TYPE_ORDER,
+ "Doubled destination prefix component",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_UNKNOWN_COMPONENT,
+ "Unknown component of type number 14",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
+ 14 /*something new*/, 0x80, 0x55,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_UNKNOWN_COMPONENT,
+ "Label component in IPv4",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_LABEL, 0xa0, 0, 0, 0, 0x55,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "Non-zero padding in prefix",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 21, 5, 6, 0x7f,
+ FLOW_TYPE_SRC_PREFIX, 24, 5, 6, 0x7f,
+ }),
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 21, 5, 6, 0x78,
+ FLOW_TYPE_SRC_PREFIX, 24, 5, 6, 0x7f,
+ })
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "The first numeric operator has set the AND bit",
+ ((byte []) {
+ FLOW_TYPE_PORT, 0x43, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ }),
+ ((byte []) {
+ FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ })
+ ),
TS(
FLOW_ST_VALID,
- "Component of type number 13 (Label) is well-known in IPv6",
+ "Set zero bit in operator to one",
((byte []) {
- FLOW_TYPE_LABEL, 0x80, 0x55
+ FLOW_TYPE_IP_PROTOCOL, 0x89, 0x06,
+ FLOW_TYPE_FRAGMENT, 0x84, 0x03,
+ }),
+ ((byte []) {
+ FLOW_TYPE_IP_PROTOCOL, 0x81, 0x06,
+ FLOW_TYPE_FRAGMENT, 0x80, 0x03,
})
),
+ TS(
+ FLOW_ST_VALID,
+ "Set zero bit in operand to one",
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x91, 0xff, 0x3a,
+ FLOW_TYPE_FRAGMENT, 0x81, 0xff,
+ }),
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x91, 0x0f, 0x3a,
+ FLOW_TYPE_FRAGMENT, 0x81, 0x0f,
+ })
+ ),
+ };
+#undef TS
+
+ for (uint tcase = 0; tcase < ARRAY_SIZE(tset); tcase++)
+ {
+ res = flow4_decode(tset[tcase].nlri, tset[tcase].size);
+ bt_assert_msg(res == tset[tcase].expect, "Assertion (%s == %s) %s", flow_validated_state_str(res), flow_validated_state_str(tset[tcase].expect), tset[tcase].description);
+
+ if ((res == FLOW_ST_VALID) && (tset[tcase].expect == FLOW_ST_VALID))
+ {
+ int pos;
+ for (pos = 0; pos < tset[tcase].size; pos++)
+ if (tset[tcase].nlri[pos] != tset[tcase].result[pos])
+ break;
+
+ bool ok = (pos == tset[tcase].size);
+ bt_assert_msg(ok, "Assertion (pos %u: 0x%02x == 0x%02x) %s", pos, (ok ? 0 : tset[tcase].nlri[pos]), (ok ? 0 : tset[tcase].result[pos]), tset[tcase].description);
+ }
+ }
+
+ return 1;
+}
+
+static int
+t_decoding6(void)
+{
+ enum flow_validated_state res;
+
+ byte nlri1[] = {
+ FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0xc0,
+ FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
+ FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
+ FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ FLOW_TYPE_LABEL, 0x80, 0x55,
+ };
+
+ /* Isn't included destination prefix */
+ res = flow6_decode(nlri1, 0);
+ bt_assert(res == FLOW_ST_VALID);
+
+ /* Valid / Not Complete testing */
+ uint valid_sizes[] = {0, 9, 13, 16, 24, 27, 0};
+ uint valid_idx = 0;
+ for (uint size = 0; size <= sizeof(nlri1); size++)
+ {
+ res = flow6_decode(nlri1, size);
+ bt_debug("size %u, result: %s\n", size, flow_validated_state_str(res));
+ if (size == valid_sizes[valid_idx])
+ {
+ valid_idx++;
+ bt_assert(res == FLOW_ST_VALID);
+ }
+ else
+ {
+ bt_assert(res == FLOW_ST_NOT_COMPLETE);
+ }
+ }
+
+ /* Misc err tests */
+
+ struct tset {
+ enum flow_validated_state expect;
+ char *description;
+ u16 size;
+ byte *nlri;
+ byte *result;
+ };
+
+#define TS(type, msg, data, result) ((struct tset) {type, msg, sizeof(data), (data), (result)})
+ struct tset tset[] = {
+ TS(
+ FLOW_ST_EXCEED_MAX_PREFIX_LENGTH,
+ "129-length IPv6 prefix",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 129, 64, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_EXCEED_MAX_PREFIX_OFFSET,
+ "Prefix offset is higher than prefix length",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 48, 64, 0x40, 0x12, 0x34
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_EXCEED_MAX_VALUE_LENGTH,
+ "Fragment of length 2",
+ ((byte []) {
+ FLOW_TYPE_FRAGMENT, 0x91, 00, 0x0f,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_BAD_TYPE_ORDER,
+ "Bad flowspec component type order",
+ ((byte []) {
+ FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
+ FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_BAD_TYPE_ORDER,
+ "Doubled destination prefix component",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0xc0,
+ FLOW_TYPE_DST_PREFIX, 103, 61, 0x01, 0x12, 0x34, 0x56, 0x78, 0xc0,
+ }),
+ NULL
+ ),
TS(
FLOW_ST_UNKNOWN_COMPONENT,
"Unknown component of type number 14",
((byte []) {
- FLOW_TYPE_LABEL, 0x80, 0x55,
+ FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
14 /*something new*/, 0x80, 0x55,
+ }),
+ NULL
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "Label component is well-known in IPv6",
+ ((byte []) {
+ FLOW_TYPE_LABEL, 0xa0, 0, 0, 0, 0x55,
+ }),
+ ((byte []) {
+ FLOW_TYPE_LABEL, 0xa0, 0, 0, 0, 0x55,
+ })
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "Non-zero padding in prefix",
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 43, 16, 0x40, 0x12, 0x34, 0x7c,
+ }),
+ ((byte []) {
+ FLOW_TYPE_DST_PREFIX, 43, 16, 0x40, 0x12, 0x34, 0x60,
+ })
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "The first numeric operator has set the AND bit",
+ ((byte []) {
+ FLOW_TYPE_PORT, 0x43, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90
+ }),
+ ((byte []) {
+ FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ })
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "Set zero bit in operator to one",
+ ((byte []) {
+ FLOW_TYPE_NEXT_HEADER, 0x89, 0x06,
+ FLOW_TYPE_FRAGMENT, 0x84, 0x02,
+ }),
+ ((byte []) {
+ FLOW_TYPE_IP_PROTOCOL, 0x81, 0x06,
+ FLOW_TYPE_FRAGMENT, 0x80, 0x02,
})
- )
+ ),
+ TS(
+ FLOW_ST_VALID,
+ "Set zero bit in operand to one",
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x91, 0xff, 0x3a,
+ FLOW_TYPE_FRAGMENT, 0x81, 0xff,
+ }),
+ ((byte []) {
+ FLOW_TYPE_TCP_FLAGS, 0x91, 0x0f, 0x3a,
+ FLOW_TYPE_FRAGMENT, 0x81, 0x0e,
+ })
+ ),
};
#undef TS
for (uint tcase = 0; tcase < ARRAY_SIZE(tset); tcase++)
{
- res = flow6_validate(tset[tcase].nlri, tset[tcase].size);
+ res = flow6_decode(tset[tcase].nlri, tset[tcase].size);
bt_assert_msg(res == tset[tcase].expect, "Assertion (%s == %s) %s", flow_validated_state_str(res), flow_validated_state_str(tset[tcase].expect), tset[tcase].description);
+
+ if ((res == FLOW_ST_VALID) && (tset[tcase].expect == FLOW_ST_VALID))
+ {
+ int pos;
+ for (pos = 0; pos < tset[tcase].size; pos++)
+ if (tset[tcase].nlri[pos] != tset[tcase].result[pos])
+ break;
+
+ bool ok = (pos == tset[tcase].size);
+ bt_assert_msg(ok, "Assertion (pos %u: 0x%02x == 0x%02x) %s", pos, (ok ? 0 : tset[tcase].nlri[pos]), (ok ? 0 : tset[tcase].result[pos]), tset[tcase].description);
+ }
}
return 1;
FLOW_TYPE_SRC_PREFIX, 8, 0, 0xc0,
FLOW_TYPE_NEXT_HEADER, 0x80, 0x06,
FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
- FLOW_TYPE_LABEL, 0x80, 0x55,
+ FLOW_TYPE_LABEL, 0xa0, 0x00, 0x00, 0x00, 0x55,
);
/* Normal order */
bt_test_suite(t_accessors6, "Testing accessors (IPv6)");
bt_test_suite(t_validation4, "Testing validation (IPv4)");
bt_test_suite(t_validation6, "Testing validation (IPv6)");
+ bt_test_suite(t_decoding4, "Testing decoding (IPv4)");
+ bt_test_suite(t_decoding6, "Testing decoding (IPv6)");
bt_test_suite(t_builder4, "Inserting components into existing Flow Specification (IPv4)");
bt_test_suite(t_builder6, "Inserting components into existing Flow Specification (IPv6)");
bt_test_suite(t_formatting4, "Formatting Flow Specification (IPv4) into text representation");