static void check_drange_node_sanity(gpointer data, gpointer user_data) { drange_node* drnode = data; struct check_drange_sanity_args *args = user_data; gint start_offset, end_offset, length; header_field_info *hfinfo; switch (drange_node_get_ending(drnode)) { case LENGTH: length = drange_node_get_length(drnode); if (length <= 0) { if (!args->err) { args->err = TRUE; start_offset = drange_node_get_start_offset(drnode); hfinfo = sttype_range_hfinfo(args->st); dfilter_fail("Range %d:%d specified for \"%s\" isn't valid, " "as length %d isn't positive", start_offset, length, hfinfo->abbrev, length); } } break; case OFFSET: /* * Make sure the start offset isn't beyond the end * offset. This applies to negative offsets too. */ /* XXX - [-ve - +ve] is probably pathological, but isn't * disallowed. * [+ve - -ve] is probably pathological too, and happens to be * disallowed. */ start_offset = drange_node_get_start_offset(drnode); end_offset = drange_node_get_end_offset(drnode); if (start_offset > end_offset) { if (!args->err) { args->err = TRUE; hfinfo = sttype_range_hfinfo(args->st); dfilter_fail("Range %d-%d specified for \"%s\" isn't valid, " "as %d is greater than %d", start_offset, end_offset, hfinfo->abbrev, start_offset, end_offset); } } break; case TO_THE_END: break; case UNINITIALIZED: default: g_assert_not_reached(); } }
static void check_function(stnode_t *st_node) { df_func_def_t *funcdef; GSList *params; guint iparam; guint nparams; funcdef = sttype_function_funcdef(st_node); params = sttype_function_params(st_node); nparams = g_slist_length(params); if (nparams < funcdef->min_nargs) { dfilter_fail("Function %s needs at least %u arguments.", funcdef->name, funcdef->min_nargs); THROW(TypeError); } else if (nparams > funcdef->max_nargs) { dfilter_fail("Function %s can only accept %u arguments.", funcdef->name, funcdef->max_nargs); THROW(TypeError); } iparam = 0; while (params) { params->data = check_param_entity(params->data); funcdef->semcheck_param_function(iparam, params->data); params = params->next; iparam++; } }
/* Check the semantics of an existence test. */ static void check_exists(dfwork_t *dfw, stnode_t *st_arg1) { #ifdef DEBUG_dfilter static guint i = 0; #endif DebugLog((" 4 check_exists() [%u]\n", i++)); switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: /* This is OK */ break; case STTYPE_STRING: case STTYPE_UNPARSED: dfilter_fail(dfw, "\"%s\" is neither a field nor a protocol name.", (char *)stnode_data(st_arg1)); THROW(TypeError); break; case STTYPE_RANGE: /* * XXX - why not? Shouldn't "eth[3:2]" mean * "check whether the 'eth' field is present and * has at least 2 bytes starting at an offset of * 3"? */ dfilter_fail(dfw, "You cannot test whether a range is present."); THROW(TypeError); break; case STTYPE_FUNCTION: /* XXX - Maybe we should change functions so they can return fields, * in which case the 'exist' should be fine. */ dfilter_fail(dfw, "You cannot test whether a function is present."); THROW(TypeError); break; case STTYPE_UNINITIALIZED: case STTYPE_TEST: case STTYPE_INTEGER: case STTYPE_FVALUE: case STTYPE_SET: case STTYPE_NUM_TYPES: g_assert_not_reached(); } }
/* Check the semantics of any relational test. */ static void check_relation(dfwork_t *dfw, const char *relation_string, gboolean allow_partial_value, FtypeCanFunc can_func, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { #ifdef DEBUG_dfilter static guint i = 0; #endif header_field_info *hfinfo; DebugLog((" 4 check_relation(\"%s\") [%u]\n", relation_string, i++)); /* Protocol can only be on LHS (for "contains" or "matches" operators). * Check to see if protocol is on RHS. This catches the case where the * user has written "fc" on the RHS, probably intending a byte value * rather than the fibre channel protocol. */ if (stnode_type_id(st_arg2) == STTYPE_FIELD) { hfinfo = (header_field_info*)stnode_data(st_arg2); if (hfinfo->type == FT_PROTOCOL) { dfilter_fail(dfw, "Protocol (\"%s\") cannot appear on right-hand side of comparison.", hfinfo->abbrev); THROW(TypeError); } } switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: check_relation_LHS_FIELD(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_STRING: check_relation_LHS_STRING(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_RANGE: check_relation_LHS_RANGE(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_UNPARSED: check_relation_LHS_UNPARSED(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_FUNCTION: check_relation_LHS_FUNCTION(dfw, relation_string, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_UNINITIALIZED: case STTYPE_TEST: case STTYPE_INTEGER: case STTYPE_FVALUE: case STTYPE_SET: default: g_assert_not_reached(); } }
gboolean dfilter_compile(const gchar *text, dfilter_t **dfp) { int token; dfilter_t *dfilter; dfwork_t *dfw; gboolean failure = FALSE; const char *depr_test; guint i; GPtrArray *deprecated; g_assert(dfp); if (!text) { *dfp = NULL; return FALSE; } dfilter_error_msg = NULL; if ( !( text = dfilter_macro_apply(text, &dfilter_error_msg) ) ) { return FALSE; } dfw = dfwork_new(); df_scanner_text(text); deprecated = g_ptr_array_new(); while (1) { df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL); token = df_lex(); /* Check for scanner failure */ if (token == SCAN_FAILED) { failure = TRUE; break; } /* Check for end-of-input */ if (token == 0) { break; } /* See if the node is deprecated */ depr_test = stnode_deprecated(df_lval); if (depr_test) { for (i = 0; i < deprecated->len; i++) { if (g_ascii_strcasecmp(depr_test, (const gchar *)g_ptr_array_index(deprecated, i)) == 0) { /* It's already in our list */ depr_test = NULL; } } } if (depr_test) { g_ptr_array_add(deprecated, g_strdup(depr_test)); } /* Give the token to the parser */ Dfilter(ParserObj, token, df_lval, dfw); /* We've used the stnode_t, so we don't want to free it */ df_lval = NULL; if (dfw->syntax_error) { failure = TRUE; break; } } /* while (1) */ /* If we created an stnode_t but didn't use it, free it; the * parser doesn't know about it and won't free it for us. */ if (df_lval) { stnode_free(df_lval); df_lval = NULL; } /* Tell the parser that we have reached the end of input; that * way, it'll reset its state for the next compile. (We want * to do that even if we got a syntax error, to make sure the * parser state is cleaned up; we don't create a new parser * object when we start a new parse, and don't destroy it when * the parse finishes.) */ Dfilter(ParserObj, 0, NULL, dfw); /* One last check for syntax error (after EOF) */ if (dfw->syntax_error) failure = TRUE; /* Reset flex */ df_scanner_cleanup(); if (failure) goto FAILURE; /* Success, but was it an empty filter? If so, discard * it and set *dfp to NULL */ if (dfw->st_root == NULL) { *dfp = NULL; for (i = 0; i < deprecated->len; ++i) { gchar* depr = (gchar*)g_ptr_array_index(deprecated,i); g_free(depr); } g_ptr_array_free(deprecated, TRUE); } else { /* Check semantics and do necessary type conversion*/ if (!dfw_semcheck(dfw)) { goto FAILURE; } /* Create bytecode */ dfw_gencode(dfw); /* Tuck away the bytecode in the dfilter_t */ dfilter = dfilter_new(); dfilter->insns = dfw->insns; dfilter->consts = dfw->consts; dfw->insns = NULL; dfw->consts = NULL; dfilter->interesting_fields = dfw_interesting_fields(dfw, &dfilter->num_interesting_fields); /* Initialize run-time space */ dfilter->num_registers = dfw->first_constant; dfilter->max_registers = dfw->next_register; dfilter->registers = g_new0(GList*, dfilter->max_registers); dfilter->attempted_load = g_new0(gboolean, dfilter->max_registers); /* Initialize constants */ dfvm_init_const(dfilter); /* Add any deprecated items */ dfilter->deprecated = deprecated; /* And give it to the user. */ *dfp = dfilter; } /* SUCCESS */ dfwork_free(dfw); return TRUE; FAILURE: if (dfw) { dfwork_free(dfw); } for (i = 0; i < deprecated->len; ++i) { gchar* depr = (gchar*)g_ptr_array_index(deprecated,i); g_free(depr); } g_ptr_array_free(deprecated, TRUE); dfilter_fail("Unable to parse filter string \"%s\".", text); *dfp = NULL; return FALSE; }
/* If the LHS of a relation test is a FUNCTION, run some checks * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FUNCTION(const char *relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo2; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; drange_node *rn; df_func_def_t *funcdef; df_func_def_t *funcdef2; GSList *params; check_function(st_arg1); type2 = stnode_type_id(st_arg2); funcdef = sttype_function_funcdef(st_arg1); ftype1 = funcdef->retval_ftype; params = sttype_function_params(st_arg1); DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string)); if (!can_func(ftype1)) { dfilter_fail("Function %s (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); } if (type2 == STTYPE_FIELD) { hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail("Function %s and %s are not of compatible types.", funcdef->name, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail("%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } } else if (type2 == STTYPE_STRING) { s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); } else { fvalue = fvalue_from_string(ftype1, s, dfilter_fail); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); } else { fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { dfilter_fail("Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); } /* Convert entire field to bytes */ new_st = stnode_new(STTYPE_RANGE, NULL); rn = drange_node_new(); drange_node_set_start_offset(rn, 0); drange_node_set_to_the_end(rn); /* st_arg1 is freed in this step */ sttype_range_set1(new_st, st_arg1, rn); sttype_test_set2_args(st_node, new_st, st_arg2); } } else if (type2 == STTYPE_FUNCTION) { funcdef2 = sttype_function_funcdef(st_arg2); ftype2 = funcdef2->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail("Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.", funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail("Return value of %s (type=%s) cannot participate in specified comparison.", funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } check_function(st_arg2); } else { g_assert_not_reached(); } }
static void check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type1, type2; header_field_info *hfinfo1, *hfinfo2; df_func_def_t *funcdef; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; drange_node *rn; type1 = stnode_type_id(st_arg1); type2 = stnode_type_id(st_arg2); hfinfo1 = sttype_range_hfinfo(st_arg1); ftype1 = hfinfo1->type; DebugLog((" 5 check_relation_LHS_RANGE(%s)\n", relation_string)); if (!ftype_can_slice(ftype1)) { dfilter_fail("\"%s\" is a %s and cannot be sliced into a sequence of bytes.", hfinfo1->abbrev, ftype_pretty_name(ftype1)); THROW(TypeError); } check_drange_sanity(st_arg1); if (type2 == STTYPE_FIELD) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)\n")); hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } /* Convert entire field to bytes */ new_st = stnode_new(STTYPE_RANGE, NULL); rn = drange_node_new(); drange_node_set_start_offset(rn, 0); drange_node_set_to_the_end(rn); /* st_arg2 is freed in this step */ sttype_range_set1(new_st, st_arg2, rn); sttype_test_set2_args(st_node, st_arg1, new_st); } } else if (type2 == STTYPE_STRING) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING)\n")); s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); } else { fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail); } if (!fvalue) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING): Could not convert from string!\n")); THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED)\n")); s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); } else { fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); } if (!fvalue) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED): Could not convert from string!\n")); THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_RANGE)\n")); check_drange_sanity(st_arg2); } else if (type2 == STTYPE_FUNCTION) { funcdef = sttype_function_funcdef(st_arg2); ftype2 = funcdef->retval_ftype; if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { dfilter_fail("Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } /* XXX should I add a new drange node? */ } check_function(st_arg2); } else { g_assert_not_reached(); } }
static void check_relation_LHS_UNPARSED(const char* relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type1, type2; header_field_info *hfinfo2; df_func_def_t *funcdef; ftenum_t ftype2; fvalue_t *fvalue; char *s; type1 = stnode_type_id(st_arg1); type2 = stnode_type_id(st_arg2); DebugLog((" 5 check_relation_LHS_UNPARSED()\n")); if (type2 == STTYPE_FIELD) { hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!can_func(ftype2)) { dfilter_fail("%s (type=%s) cannot participate in '%s' comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2), relation_string); THROW(TypeError); } s = stnode_data(st_arg1); fvalue = fvalue_from_unparsed(ftype2, s, allow_partial_value, dfilter_fail); if (!fvalue) { /* check value_string */ fvalue = mk_fvalue_from_val_string(hfinfo2, s); if (!fvalue) { THROW(TypeError); } } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, new_st, st_arg2); stnode_free(st_arg1); } else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) { /* Well now that's silly... */ dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.", stnode_data(st_arg1), stnode_data(st_arg2)); THROW(TypeError); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(st_arg2); s = stnode_data(st_arg1); fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, new_st, st_arg2); stnode_free(st_arg1); } else if (type2 == STTYPE_FUNCTION) { funcdef = sttype_function_funcdef(st_arg2); ftype2 = funcdef->retval_ftype; if (!can_func(ftype2)) { dfilter_fail("return value of function %s() (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype2), relation_string); THROW(TypeError); } s = stnode_data(st_arg1); fvalue = fvalue_from_unparsed(ftype2, s, allow_partial_value, dfilter_fail); if (!fvalue) { THROW(TypeError); } check_function(st_arg2); new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, new_st, st_arg2); stnode_free(st_arg1); } else { g_assert_not_reached(); } }
/* Try to make an fvalue from a string using a value_string or true_false_string. * This works only for ftypes that are integers. Returns the created fvalue_t* * or NULL if impossible. */ static fvalue_t* mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) { static const true_false_string default_tf = { "True", "False" }; const true_false_string *tf = &default_tf; /* Early return? */ switch(hfinfo->type) { case FT_NONE: case FT_PROTOCOL: case FT_FLOAT: case FT_DOUBLE: case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: case FT_IPv4: case FT_IPv6: case FT_IPXNET: case FT_ETHER: case FT_BYTES: case FT_UINT_BYTES: case FT_STRING: case FT_STRINGZ: case FT_EBCDIC: case FT_UINT_STRING: case FT_UINT64: case FT_INT64: case FT_PCRE: case FT_GUID: case FT_OID: return NULL; case FT_BOOLEAN: case FT_FRAMENUM: case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: break; case FT_NUM_TYPES: g_assert_not_reached(); } /* Reset the dfilter error message, since *something* interesting * will happen, and the error message will be more interesting than * any error message I happen to have now. */ dfilter_error_msg = NULL; /* TRUE/FALSE *always* exist for FT_BOOLEAN. */ if (hfinfo->type == FT_BOOLEAN) { if (hfinfo->strings) { tf = hfinfo->strings; } if (g_ascii_strcasecmp(s, tf->true_string) == 0) { return mk_uint32_fvalue(TRUE); } else if (g_ascii_strcasecmp(s, tf->false_string) == 0) { return mk_uint32_fvalue(FALSE); } else { dfilter_fail("\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); return NULL; } } /* Do val_strings exist? */ if (!hfinfo->strings) { dfilter_fail("%s cannot accept strings as values.", hfinfo->abbrev); return NULL; } if (hfinfo->display & BASE_RANGE_STRING) { dfilter_fail("\"%s\" cannot accept [range] strings as values.", hfinfo->abbrev); return NULL; } else { const value_string *vals = hfinfo->strings; while (vals->strptr != NULL) { if (g_ascii_strcasecmp(s, vals->strptr) == 0) { return mk_uint32_fvalue(vals->value); } vals++; } dfilter_fail("\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); } return NULL; }
/* Check the semantics of any type of TEST */ static void check_test(stnode_t *st_node) { test_op_t st_op; stnode_t *st_arg1, *st_arg2; #ifdef DEBUG_dfilter static guint i = 0; #endif DebugLog((" 3 check_test(stnode_t *st_node = %p) [%u]\n", st_node, i)); sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2); switch (st_op) { case TEST_OP_UNINITIALIZED: g_assert_not_reached(); break; case TEST_OP_EXISTS: check_exists(st_arg1); break; case TEST_OP_NOT: semcheck(st_arg1); break; case TEST_OP_AND: case TEST_OP_OR: semcheck(st_arg1); semcheck(st_arg2); break; case TEST_OP_EQ: check_relation("==", FALSE, ftype_can_eq, st_node, st_arg1, st_arg2); break; case TEST_OP_NE: check_relation("!=", FALSE, ftype_can_ne, st_node, st_arg1, st_arg2); break; case TEST_OP_GT: check_relation(">", FALSE, ftype_can_gt, st_node, st_arg1, st_arg2); break; case TEST_OP_GE: check_relation(">=", FALSE, ftype_can_ge, st_node, st_arg1, st_arg2); break; case TEST_OP_LT: check_relation("<", FALSE, ftype_can_lt, st_node, st_arg1, st_arg2); break; case TEST_OP_LE: check_relation("<=", FALSE, ftype_can_le, st_node, st_arg1, st_arg2); break; case TEST_OP_BITWISE_AND: check_relation("&", FALSE, ftype_can_bitwise_and, st_node, st_arg1, st_arg2); break; case TEST_OP_CONTAINS: check_relation("contains", TRUE, ftype_can_contains, st_node, st_arg1, st_arg2); break; case TEST_OP_MATCHES: #ifdef HAVE_LIBPCRE check_relation("matches", TRUE, ftype_can_matches, st_node, st_arg1, st_arg2); #else dfilter_fail("This Wireshark version does not support the \"matches\" operation."); THROW(TypeError); #endif break; default: g_assert_not_reached(); } DebugLog((" 3 check_test(stnode_t *st_node = %p) [%u] - End\n", st_node, i++)); }
static void check_relation_LHS_RANGE(const char *relation_string, FtypeCanFunc can_func _U_, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo1, *hfinfo2; df_func_def_t *funcdef; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; drange_node *rn; int len_range; type2 = stnode_type_id(st_arg2); hfinfo1 = sttype_range_hfinfo(st_arg1); ftype1 = hfinfo1->type; DebugLog((" 5 check_relation_LHS_RANGE(%s)\n", relation_string)); if (!ftype_can_slice(ftype1)) { dfilter_fail("\"%s\" is a %s and cannot be sliced into a sequence of bytes.", hfinfo1->abbrev, ftype_pretty_name(ftype1)); THROW(TypeError); } check_drange_sanity(st_arg1); if (type2 == STTYPE_FIELD) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)\n")); hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } /* Convert entire field to bytes */ new_st = stnode_new(STTYPE_RANGE, NULL); rn = drange_node_new(); drange_node_set_start_offset(rn, 0); drange_node_set_to_the_end(rn); /* st_arg2 is freed in this step */ sttype_range_set1(new_st, st_arg2, rn); sttype_test_set2_args(st_node, st_arg1, new_st); } } else if (type2 == STTYPE_STRING) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING)\n")); s = stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); } else { fvalue = fvalue_from_string(FT_BYTES, s, dfilter_fail); } if (!fvalue) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_STRING): Could not convert from string!\n")); THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED)\n")); s = stnode_data(st_arg2); len_range = drange_get_total_length(sttype_range_drange(st_arg1)); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); } /* The RHS should be FT_BYTES. However, there is a special case where * the range slice on the LHS is one byte long. In that case, it is natural * for the user to specify a normal hex integer on the RHS, with the "0x" * notation, as in "slice[0] == 0x10". We can't allow this for any * slices that are longer than one byte, because then we'd have to know * which endianness the byte string should be in. */ else if (len_range == 1 && strlen(s) == 4 && strncmp(s, "0x", 2) == 0) { /* Even if the RHS string starts with "0x", it still could fail to * be an integer. Try converting it here. */ fvalue = fvalue_from_unparsed(FT_UINT8, s, allow_partial_value, dfilter_fail); if (fvalue) { FVALUE_FREE(fvalue); /* The value doees indeed fit into 8 bits. Create a BYTE_STRING * from it. Since we know that the last 2 characters are a valid * hex string, just use those directly. */ fvalue = fvalue_from_unparsed(FT_BYTES, s+2, allow_partial_value, dfilter_fail); } } else { fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); } if (!fvalue) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_UNPARSED): Could not convert from string!\n")); THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_RANGE)\n")); check_drange_sanity(st_arg2); } else if (type2 == STTYPE_FUNCTION) { funcdef = sttype_function_funcdef(st_arg2); ftype2 = funcdef->retval_ftype; if (!is_bytes_type(ftype2)) { if (!ftype_can_slice(ftype2)) { dfilter_fail("Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } /* XXX should I add a new drange node? */ } check_function(st_arg2); } else { g_assert_not_reached(); } }
/* Try to make an fvalue from a string using a value_string or true_false_string. * This works only for ftypes that are integers. Returns the created fvalue_t* * or NULL if impossible. */ static fvalue_t* mk_fvalue_from_val_string(header_field_info *hfinfo, char *s) { static const true_false_string default_tf = { "True", "False" }; const true_false_string *tf = &default_tf; /* Early return? */ switch(hfinfo->type) { case FT_NONE: case FT_PROTOCOL: case FT_FLOAT: case FT_DOUBLE: case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: case FT_IPv4: case FT_IPv6: case FT_IPXNET: case FT_ETHER: case FT_BYTES: case FT_UINT_BYTES: case FT_STRING: case FT_STRINGZ: case FT_UINT_STRING: case FT_UINT64: case FT_INT64: case FT_EUI64: case FT_PCRE: case FT_GUID: case FT_OID: return NULL; case FT_BOOLEAN: case FT_FRAMENUM: case FT_UINT8: case FT_UINT16: case FT_UINT24: case FT_UINT32: case FT_INT8: case FT_INT16: case FT_INT24: case FT_INT32: break; case FT_NUM_TYPES: g_assert_not_reached(); } /* TRUE/FALSE *always* exist for FT_BOOLEAN. */ if (hfinfo->type == FT_BOOLEAN) { if (hfinfo->strings) { tf = hfinfo->strings; } if (g_ascii_strcasecmp(s, tf->true_string) == 0) { return mk_uint32_fvalue(TRUE); } else if (g_ascii_strcasecmp(s, tf->false_string) == 0) { return mk_uint32_fvalue(FALSE); } else { dfilter_error_msg = NULL; /* Prefer this error message */ dfilter_fail("\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); return NULL; } } /* Do val_strings exist? */ if (!hfinfo->strings) { dfilter_fail("%s cannot accept strings as values.", hfinfo->abbrev); return NULL; } /* Reset the dfilter error message, since *something* interesting * will happen, and the error message will be more interesting than * any error message I happen to have now. */ dfilter_error_msg = NULL; if (hfinfo->display & BASE_RANGE_STRING) { dfilter_fail("\"%s\" cannot accept [range] strings as values.", hfinfo->abbrev); } else if (hfinfo->display == BASE_CUSTOM) { /* If a user wants to match against a custom string, we would * somehow have to have the integer value here to pass it in * to the custom-display function. But we don't have an * integer, we have the string they're trying to match. * -><- */ dfilter_fail("\"%s\" cannot accept [custom] strings as values.", hfinfo->abbrev); } else { const value_string *vals = hfinfo->strings; if (hfinfo->display & BASE_EXT_STRING) vals = VALUE_STRING_EXT_VS_P((value_string_ext *) vals); while (vals->strptr != NULL) { if (g_ascii_strcasecmp(s, vals->strptr) == 0) { return mk_uint32_fvalue(vals->value); } vals++; } dfilter_fail("\"%s\" cannot be found among the possible values for %s.", s, hfinfo->abbrev); } return NULL; }
/* If the LHS of a relation test is a FIELD, run some checks * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo1, *hfinfo2; df_func_def_t *funcdef; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; type2 = stnode_type_id(st_arg2); hfinfo1 = (header_field_info*)stnode_data(st_arg1); ftype1 = hfinfo1->type; DebugLog((" 5 check_relation_LHS_FIELD(%s)\n", relation_string)); if (!can_func(ftype1)) { dfilter_fail("%s (type=%s) cannot participate in '%s' comparison.", hfinfo1->abbrev, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); } if (type2 == STTYPE_FIELD) { hfinfo2 = (header_field_info*)stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail("%s and %s are not of compatible types.", hfinfo1->abbrev, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail("%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } } else if (type2 == STTYPE_STRING) { s = (char *)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_string(FT_PCRE, s, dfilter_fail); } else { fvalue = fvalue_from_string(ftype1, s, dfilter_fail); if (!fvalue) { /* check value_string */ fvalue = mk_fvalue_from_val_string(hfinfo1, s); } } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { s = (char *)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = fvalue_from_unparsed(FT_PCRE, s, FALSE, dfilter_fail); } else { do { fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail); if (!fvalue) { /* check value_string */ fvalue = mk_fvalue_from_val_string(hfinfo1, s); } if (!fvalue) { /* Try another field with the same name */ if (hfinfo1->same_name_prev_id != -1) { hfinfo1 = proto_registrar_get_nth(hfinfo1->same_name_prev_id); ftype1 = hfinfo1->type; } else { break; } } } while (!fvalue); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { dfilter_fail("\"%s\" is a %s and cannot be converted into a sequence of bytes.", hfinfo1->abbrev, ftype_pretty_name(ftype1)); THROW(TypeError); } /* Convert entire field to bytes */ new_st = convert_to_bytes(st_arg1); sttype_test_set2_args(st_node, new_st, st_arg2); } } else if (type2 == STTYPE_FUNCTION) { funcdef = sttype_function_funcdef(st_arg2); ftype2 = funcdef->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail("%s (type=%s) and return value of %s() (type=%s) are not of compatible types.", hfinfo1->abbrev, ftype_pretty_name(ftype1), funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } if (!can_func(ftype2)) { dfilter_fail("return value of %s() (type=%s) cannot participate in specified comparison.", funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } check_function(st_arg2); } else { g_assert_not_reached(); } }
/* If the LHS of a relation test is a FIELD, run some checks * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FIELD(dfwork_t *dfw, const char *relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo1, *hfinfo2; df_func_def_t *funcdef; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; type2 = stnode_type_id(st_arg2); hfinfo1 = (header_field_info*)stnode_data(st_arg1); ftype1 = hfinfo1->type; if (stnode_type_id(st_node) == STTYPE_TEST) { DebugLog((" 5 check_relation_LHS_FIELD(%s)\n", relation_string)); } else { DebugLog((" 6 check_relation_LHS_FIELD(%s)\n", relation_string)); } if (!can_func(ftype1)) { dfilter_fail(dfw, "%s (type=%s) cannot participate in '%s' comparison.", hfinfo1->abbrev, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); } if (type2 == STTYPE_FIELD) { hfinfo2 = (header_field_info*)stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail(dfw, "%s and %s are not of compatible types.", hfinfo1->abbrev, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } } else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) { s = (char *)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ if (type2 == STTYPE_STRING) fvalue = dfilter_fvalue_from_string(dfw, FT_PCRE, s); else fvalue = dfilter_fvalue_from_unparsed(dfw, FT_PCRE, s, FALSE); } else { /* Skip incompatible fields */ while (hfinfo1->same_name_prev_id != -1 && ((type2 == STTYPE_STRING && ftype1 != FT_STRING && ftype1!= FT_STRINGZ) || (type2 != STTYPE_STRING && (ftype1 == FT_STRING || ftype1== FT_STRINGZ)))) { hfinfo1 = proto_registrar_get_nth(hfinfo1->same_name_prev_id); ftype1 = hfinfo1->type; } if (type2 == STTYPE_STRING) fvalue = dfilter_fvalue_from_string(dfw, ftype1, s); else fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, s, allow_partial_value); if (!fvalue) { /* check value_string */ fvalue = mk_fvalue_from_val_string(dfw, hfinfo1, s); } } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); if (stnode_type_id(st_node) == STTYPE_TEST) { sttype_test_set2_args(st_node, st_arg1, new_st); } else { sttype_set_replace_element(st_node, st_arg2, new_st); } stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(dfw, st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { dfilter_fail(dfw, "\"%s\" is a %s and cannot be converted into a sequence of bytes.", hfinfo1->abbrev, ftype_pretty_name(ftype1)); THROW(TypeError); } /* Convert entire field to bytes */ new_st = convert_to_bytes(st_arg1); sttype_test_set2_args(st_node, new_st, st_arg2); } } else if (type2 == STTYPE_FUNCTION) { funcdef = sttype_function_funcdef(st_arg2); ftype2 = funcdef->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail(dfw, "%s (type=%s) and return value of %s() (type=%s) are not of compatible types.", hfinfo1->abbrev, ftype_pretty_name(ftype1), funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } if (!can_func(ftype2)) { dfilter_fail(dfw, "return value of %s() (type=%s) cannot participate in specified comparison.", funcdef->name, ftype_pretty_name(ftype2)); THROW(TypeError); } check_function(dfw, st_arg2); } else if (type2 == STTYPE_SET) { GSList *nodelist; /* A set should only ever appear on RHS of 'in' operation */ if (strcmp(relation_string, "in") != 0) { g_assert_not_reached(); } /* Attempt to interpret one element of the set at a time */ nodelist = (GSList*)stnode_data(st_arg2); while (nodelist) { stnode_t *node = (stnode_t*)nodelist->data; /* Don't let a range on the RHS affect the LHS field. */ if (stnode_type_id(node) == STTYPE_RANGE) { dfilter_fail(dfw, "A range may not appear inside a set."); THROW(TypeError); break; } check_relation_LHS_FIELD(dfw, "==", can_func, allow_partial_value, st_arg2, st_arg1, node); nodelist = g_slist_next(nodelist); } } else { g_assert_not_reached(); } }
/* If the LHS of a relation test is a FUNCTION, run some checks * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FUNCTION(dfwork_t *dfw, const char *relation_string, FtypeCanFunc can_func, gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; sttype_id_t type2; header_field_info *hfinfo2; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; df_func_def_t *funcdef; df_func_def_t *funcdef2; /* GSList *params; */ check_function(dfw, st_arg1); type2 = stnode_type_id(st_arg2); funcdef = sttype_function_funcdef(st_arg1); ftype1 = funcdef->retval_ftype; /* params = */sttype_function_params(st_arg1); /* XXX: is this done for the side-effect ? */ DebugLog((" 5 check_relation_LHS_FUNCTION(%s)\n", relation_string)); if (!can_func(ftype1)) { dfilter_fail(dfw, "Function %s (type=%s) cannot participate in '%s' comparison.", funcdef->name, ftype_pretty_name(ftype1), relation_string); THROW(TypeError); } if (type2 == STTYPE_FIELD) { hfinfo2 = (header_field_info*)stnode_data(st_arg2); ftype2 = hfinfo2->type; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail(dfw, "Function %s and %s are not of compatible types.", funcdef->name, hfinfo2->abbrev); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail(dfw, "%s (type=%s) cannot participate in specified comparison.", hfinfo2->abbrev, ftype_pretty_name(ftype2)); THROW(TypeError); } } else if (type2 == STTYPE_STRING) { s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = dfilter_fvalue_from_string(dfw, FT_PCRE, s); } else { fvalue = dfilter_fvalue_from_string(dfw, ftype1, s); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_UNPARSED) { s = (char*)stnode_data(st_arg2); if (strcmp(relation_string, "matches") == 0) { /* Convert to a FT_PCRE */ fvalue = dfilter_fvalue_from_unparsed(dfw, FT_PCRE, s, FALSE); } else { fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, s, allow_partial_value); } if (!fvalue) { THROW(TypeError); } new_st = stnode_new(STTYPE_FVALUE, fvalue); sttype_test_set2_args(st_node, st_arg1, new_st); stnode_free(st_arg2); } else if (type2 == STTYPE_RANGE) { check_drange_sanity(dfw, st_arg2); if (!is_bytes_type(ftype1)) { if (!ftype_can_slice(ftype1)) { dfilter_fail(dfw, "Function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); } /* Convert function result to bytes */ new_st = convert_to_bytes(st_arg1); sttype_test_set2_args(st_node, new_st, st_arg2); } } else if (type2 == STTYPE_FUNCTION) { funcdef2 = sttype_function_funcdef(st_arg2); ftype2 = funcdef2->retval_ftype; if (!compatible_ftypes(ftype1, ftype2)) { dfilter_fail(dfw, "Return values of function %s (type=%s) and function %s (type=%s) are not of compatible types.", funcdef->name, ftype_pretty_name(ftype1), funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } /* Do this check even though you'd think that if * they're compatible, then can_func() would pass. */ if (!can_func(ftype2)) { dfilter_fail(dfw, "Return value of %s (type=%s) cannot participate in specified comparison.", funcdef2->name, ftype_pretty_name(ftype2)); THROW(TypeError); } check_function(dfw, st_arg2); } else if (type2 == STTYPE_SET) { dfilter_fail(dfw, "Only a field may be tested for membership in a set."); THROW(TypeError); } else { g_assert_not_reached(); } }