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; stnode_t *entity1; header_field_info *hfinfo1, *hfinfo2; ftenum_t ftype1, ftype2; fvalue_t *fvalue; char *s; int len_range; DebugLog((" 5 check_relation_LHS_RANGE(%s)\n", relation_string)); type2 = stnode_type_id(st_arg2); entity1 = sttype_range_entity(st_arg1); if (entity1 && stnode_type_id(entity1) == STTYPE_FIELD) { hfinfo1 = (header_field_info *)stnode_data(entity1); ftype1 = hfinfo1->type; 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); } } else if (entity1 && stnode_type_id(entity1) == STTYPE_FUNCTION) { df_func_def_t *funcdef = sttype_function_funcdef(entity1); ftype1 = funcdef->retval_ftype; if (!ftype_can_slice(ftype1)) { dfilter_fail("Return value of function \"%s\" is a %s and cannot be converted into a sequence of bytes.", funcdef->name, ftype_pretty_name(ftype1)); THROW(TypeError); } check_function(entity1); } else { dfilter_fail("Range is not supported, details: " G_STRLOC " entity: %p of type %d", entity1, entity1 ? (int) stnode_type_id(entity1) : -1); THROW(TypeError); } check_drange_sanity(st_arg1); if (type2 == STTYPE_FIELD) { DebugLog((" 5 check_relation_LHS_RANGE(type2 = STTYPE_FIELD)\n")); hfinfo2 = (header_field_info*)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 = convert_to_bytes(st_arg2); 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 = (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(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 = (char*)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) { df_func_def_t *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); } /* Convert function result to bytes */ new_st = convert_to_bytes(st_arg2); sttype_test_set2_args(st_node, st_arg1, new_st); } check_function(st_arg2); } 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(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(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("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("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 = (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) { 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 { 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 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("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(); } }
/* 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(); } }