TEST(TestIronBee, test_data_indexed) { ib_engine_t *ib; ib_data_config_t *dataconfig; ib_data_t *data; ib_field_t *f; size_t i; size_t j; ib_num_t n; ibtest_engine_create(&ib); ASSERT_EQ(IB_OK, ib_data_config_create(ib_engine_pool_main_get(ib), & dataconfig)); ASSERT_EQ(IB_OK, ib_data_register_indexed_ex(dataconfig, "foo", 3, &i)); ASSERT_EQ(IB_OK, ib_data_lookup_index(dataconfig, "foo", &j)); ASSERT_EQ(i, j); ASSERT_EQ(IB_ENOENT, ib_data_lookup_index(dataconfig, "bar", NULL)); ASSERT_EQ(IB_EINVAL, ib_data_register_indexed(dataconfig, "foo")); ASSERT_EQ(IB_OK, ib_data_create(dataconfig, ib_engine_pool_main_get(ib), &data)); ASSERT_TRUE(data); ASSERT_EQ(IB_OK, ib_data_add_num(data, "foo", 5, NULL)); ASSERT_EQ(IB_OK, ib_data_get_indexed(data, i, &f)); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_num_out(&n))); ASSERT_EQ(5, n); ASSERT_EQ(IB_OK, ib_data_get(data, "foo", &f)); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_num_out(&n))); ASSERT_EQ(5, n); }
TEST_F(TestIBUtilField, AliasBytestr) { const char s1[] = "hello"; const char s2[] = "bye"; ib_field_t *f; const ib_bytestr_t *obs; ib_status_t rc; ib_bytestr_t *bs; uint8_t *copy; copy = (uint8_t *)ib_mm_strdup(MM(), "x"); rc = ib_field_create_bytestr_alias(&f, MM(), IB_S2SL("foo"), copy, 0); ASSERT_EQ(IB_OK, rc); rc = ib_bytestr_dup_nulstr(&bs, MM(), s1); ASSERT_EQ(IB_OK, rc); rc = ib_field_setv(f, bs); ASSERT_EQ(IB_OK, rc); rc = ib_field_value(f, ib_ftype_bytestr_out(&obs)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(strlen(s1), ib_bytestr_length(obs)); ASSERT_EQ(0, memcmp(s1, ib_bytestr_const_ptr(obs), ib_bytestr_length(obs)) ); rc = ib_bytestr_dup_nulstr(&bs, MM(), s2); ASSERT_EQ(IB_OK, rc); rc = ib_field_setv(f, bs); ASSERT_EQ(IB_OK, rc); rc = ib_field_value(f, ib_ftype_bytestr_out(&obs)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(strlen(s2), ib_bytestr_length(obs)); ASSERT_EQ(0, memcmp(s2, ib_bytestr_const_ptr(obs), ib_bytestr_length(obs)) ); }
TEST_F(TestIBUtilField, Alias) { ib_num_t num1; ib_num_t num2; ib_float_t flt1; ib_float_t flt2; char *s = NULL; const char *v; ib_field_t *f; ib_status_t rc; rc = ib_field_create_alias(&f, MM(), "foo", 3, IB_FTYPE_NULSTR, ib_ftype_nulstr_mutable_out(&s)); ASSERT_EQ(IB_OK, rc); v = "hello"; rc = ib_field_setv(f, ib_ftype_nulstr_in(v)); ASSERT_EQ(IB_OK, rc); ASSERT_STREQ(v, s); /* * Alias a numeric field */ num1 = 1; rc = ib_field_create_alias(&f, MM(), "num", 3, IB_FTYPE_NUM, ib_ftype_num_in(&num1)); ASSERT_EQ(IB_OK, rc); rc = ib_field_value(f, ib_ftype_num_out(&num2)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(num1, num2); num1 = 3; rc = ib_field_value(f, ib_ftype_num_out(&num2)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(num1, num2); /* * Alias a floating point field */ flt1 = 1.1; rc = ib_field_create_alias(&f, MM(), "flt", 3, IB_FTYPE_FLOAT, ib_ftype_float_in(&flt1)); ASSERT_EQ(IB_OK, rc); rc = ib_field_value(f, ib_ftype_float_out(&flt2)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(flt1, flt2); flt1 = 1.5; rc = ib_field_value(f, ib_ftype_float_out(&flt2)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(flt1, flt2); }
// Test pattern matching a field. TEST(TestIronBee, test_data_pcre) { ib_engine_t *ib; ib_data_config_t *dataconfig; ib_data_t *data; ib_field_t *list_field; ib_field_t *out_field; ib_list_t *list; ib_list_t *out_list; ib_field_t *field1; ib_field_t *field2; ib_field_t *field3; ib_num_t num1 = 1; ib_num_t num2 = 2; ib_num_t num3 = 3; ibtest_engine_create(&ib); ASSERT_EQ(IB_OK, ib_data_config_create(ib_engine_pool_main_get(ib), & dataconfig)); ASSERT_EQ(IB_OK, ib_data_create(dataconfig, ib_engine_pool_main_get(ib), &data)); ASSERT_TRUE(data); ASSERT_IB_OK( ib_field_create(&field1, ib_data_pool(data), "field1", 6, IB_FTYPE_NUM, &num1)); ASSERT_IB_OK( ib_field_create(&field2, ib_data_pool(data), "field2", 6, IB_FTYPE_NUM, &num2)); ASSERT_IB_OK( ib_field_create(&field3, ib_data_pool(data), "field3", 6, IB_FTYPE_NUM, &num3)); ASSERT_IB_OK(ib_data_add_list(data, "ARGV", &list_field)); ASSERT_IB_OK(ib_data_get(data, "ARGV", &out_field)); ASSERT_IB_OK(ib_field_value(list_field, &list)); ASSERT_IB_OK(ib_list_push(list, field1)); ASSERT_IB_OK(ib_list_push(list, field2)); ASSERT_IB_OK(ib_list_push(list, field3)); ASSERT_IB_OK(ib_data_get(data, "ARGV:/.*(1|3)/", &out_field)); ASSERT_IB_OK(ib_field_value(out_field, &out_list)); ASSERT_NE(list, out_list); /* Make sure it's a different list. */ ASSERT_EQ(2U, IB_LIST_ELEMENTS(out_list)); out_field = (ib_field_t *) IB_LIST_FIRST(out_list)->data; ASSERT_FALSE(memcmp(out_field->name, field1->name, field1->nlen)); out_field = (ib_field_t *) IB_LIST_LAST(out_list)->data; ASSERT_FALSE(memcmp(out_field->name, field3->name, field3->nlen)); ibtest_engine_destroy(ib); }
TEST_F(PcreModuleTest, test_match_capture) { ib_field_t *ib_field; const ib_bytestr_t *ib_bytestr; ib_status_t rc; /* Check :0 */ ib_field = getTarget1(IB_TX_CAPTURE":0"); ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field); ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type); /* Check :1 */ ib_field = getTarget1(IB_TX_CAPTURE":1"); ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field); ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type); /* Check :2 */ ib_field = getTarget1(IB_TX_CAPTURE":2"); ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field); ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type); rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr)); ASSERT_EQ(IB_OK, rc); /* Check that a value is over written correctly. */ ASSERT_EQ("4", std::string( reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)), ib_bytestr_length(ib_bytestr) )); ib_field = getTarget1(IB_TX_CAPTURE":3"); ASSERT_FALSE(ib_field); }
long double ConstField::value_as_float() const { Internal::check_type(FLOAT, type()); long double v; throw_if_error(ib_field_value(ib(), ib_ftype_float_out(&v))); return v; }
int64_t ConstField::value_as_number() const { Internal::check_type(NUMBER, type()); int64_t v; throw_if_error(ib_field_value(ib(), ib_ftype_num_out(&v))); return v; }
uint64_t ConstField::value_as_time() const { Internal::check_type(TIME, type()); uint64_t v; throw_if_error(ib_field_value(ib(), ib_ftype_time_out(&v))); return v; }
ib_status_t test_execute_fn(const ib_rule_exec_t *rule_exec, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { char *searchstr = (char *)data; const char* s; ib_status_t rc; if (field->type != IB_FTYPE_NULSTR) { return IB_EINVAL; } rc = ib_field_value(field, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { return rc; } if (strstr(s, searchstr) == NULL) { *result = 0; } else { *result = 1; } return IB_OK; }
ib_status_t test_execute_fn( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { char *searchstr = (char *)instance_data; const char* s; ib_status_t rc; if (field->type != IB_FTYPE_NULSTR) { return IB_EINVAL; } rc = ib_field_value(field, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { return rc; } if (strstr(s, searchstr) == NULL) { *result = 0; } else { *result = 1; } return IB_OK; }
TEST_F(XRulesTest, SetFlag) { ib_field_t *field; ib_num_t num; ib_var_target_t *target; const ib_list_t *list; std::string config = std::string( "LogLevel DEBUG\n" "LoadModule \"ibmod_persistence_framework.so\"\n" "LoadModule \"ibmod_init_collection.so\"\n" "LoadModule \"ibmod_xrules.so\"\n" "InitCollection GeoIP vars: country_code=US\n" "SensorId B9C1B52B-C24A-4309-B9F9-0EF4CD577A3E\n" "SensorName UnitTesting\n" "SensorHostname unit-testing.sensor.tld\n" /* Note that both rules should fire and result in a single entry. */ "XRulePath / EnableRequestParamInspection priority=1\n" "XRuleGeo US EnableRequestParamInspection priority=1\n" "<Site test-site>\n" " SiteId AAAABBBB-1111-2222-3333-000000000000\n" " Hostname somesite.com\n" "</Site>\n" ); configureIronBeeByString(config.c_str()); performTx(); ASSERT_TRUE(ib_tx); ASSERT_TRUE(ib_tx->flags & IB_TX_FINSPECT_REQPARAMS); ASSERT_EQ( IB_OK, ib_var_target_acquire_from_string( &target, ib_tx->mp, ib_var_store_config(ib_tx->var_store), "FLAGS:inspectRequestParams", strlen("FLAGS:inspectRequestParams"), NULL, NULL) ); ASSERT_EQ( IB_OK, ib_var_target_get_const( target, &list, ib_tx->mp, ib_tx->var_store) ); ASSERT_EQ(1U, ib_list_elements(list)); field = (ib_field_t *)ib_list_node_data_const(ib_list_first_const(list)); ASSERT_EQ(IB_FTYPE_NUM, field->type); ASSERT_EQ( IB_OK, ib_field_value(field, ib_ftype_num_out(&num)) ); ASSERT_EQ(1, num); }
const char* ConstField::value_as_null_string() const { Internal::check_type(NULL_STRING, type()); const char* v; throw_if_error(ib_field_value( ib(), ib_ftype_nulstr_out(&v) )); return v; }
ConstByteString ConstField::value_as_byte_string() const { Internal::check_type(BYTE_STRING, type()); const ib_bytestr_t* v; throw_if_error(ib_field_value( ib(), ib_ftype_bytestr_out(&v) )); return ConstByteString(v); }
/// @test Test util field library - ib_field_create() ib_field_create() TEST_F(TestIBUtilField, test_field_create) { ib_field_t *f; ib_status_t rc; const char *nulstrval = "TestValue"; ib_num_t numval = 5; ib_bytestr_t *bytestrval; const char *nulout; const char *nulcopy; nulcopy = ib_mm_strdup(MM(), nulstrval); ASSERT_STRNE(NULL, nulcopy); rc = ib_field_create(&f, MM(), IB_S2SL("test_nulstr"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(nulcopy)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(11UL, f->nlen); ASSERT_EQ(0, memcmp("test_nulstr", f->name, 11)); rc = ib_field_value(f, ib_ftype_nulstr_out(&nulout)); ASSERT_EQ(IB_OK, rc); ASSERT_STREQ(nulstrval, nulout); rc = ib_field_create(&f, MM(), IB_S2SL("test_num"), IB_FTYPE_NUM, ib_ftype_num_in(&numval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(8UL, f->nlen); ASSERT_EQ(0, memcmp("test_num", f->name, 8)); rc = ib_bytestr_dup_mem(&bytestrval, MM(), (uint8_t *)nulstrval, strlen(nulstrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); rc = ib_field_create(&f, MM(), IB_S2SL("test_bytestr"), IB_FTYPE_BYTESTR, ib_ftype_bytestr_in(bytestrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(12UL, f->nlen); ASSERT_EQ(0, memcmp("test_bytestr", f->name, 12)); rc = ib_field_create(&f, MM(), IB_S2SL("test_nulstr_ex"), IB_FTYPE_NULSTR, ib_ftype_nulstr_in(nulstrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); rc = ib_field_create(&f, MM(), IB_S2SL("test_num_ex"), IB_FTYPE_NUM, ib_ftype_num_in(&numval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); rc = ib_field_create(&f, MM(), IB_S2SL("test_bytestr_ex"), IB_FTYPE_BYTESTR, ib_ftype_bytestr_in(bytestrval)); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); }
TEST_F(CoreActionTest, setVarMult) { ib_field_t *f; ib_num_t n; ASSERT_EQ(IB_OK, ib_data_get(ib_conn->tx->dpi, "c", &f)); ASSERT_EQ(IB_FTYPE_NUM, f->type); ib_field_value(f, ib_ftype_num_out(&n)); ASSERT_EQ(2, n); }
static ib_status_t sqli_op_execute( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { assert(tx != NULL); assert(field != NULL); assert(result != NULL); sfilter sf; ib_bytestr_t *bs; ib_status_t rc; const sqli_pattern_set_t *ps = (const sqli_pattern_set_t *)instance_data; *result = 0; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field->type != IB_FTYPE_BYTESTR) { return IB_OK; } rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs)); if (rc != IB_OK) { return rc; } /* Run through libinjection. */ libinjection_sqli_init( &sf, (const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), FLAG_NONE ); if (ps != NULL ) { libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)ps); } if ( libinjection_is_sqli(&sf) ) { ib_log_debug_tx(tx, "Matched SQLi fingerprint: %s", sf.fingerprint); *result = 1; } return IB_OK; }
/// @test Test util field library - ib_field_from_string() TEST_F(TestIBUtilField, test_field_from_string) { ib_field_t *f; ib_status_t rc; ib_num_t fnum; ib_float_t ffloat; const char *fnulstr; rc = ib_field_from_string(MM(), IB_S2SL("test_num"), "11", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NUM, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_num_out(&fnum))); ASSERT_EQ(11, fnum); rc = ib_field_from_string(MM(), IB_S2SL("test_num"), "-11", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NUM, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_num_out(&fnum))); ASSERT_EQ(-11, fnum); rc = ib_field_from_string(MM(), IB_S2SL("test_float"), "1.0", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_FLOAT, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_float_out(&ffloat))); ASSERT_EQ(1.0, ffloat); rc = ib_field_from_string(MM(), IB_S2SL("test_num"), "-1.0", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_FLOAT, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_float_out(&ffloat))); ASSERT_EQ(-1.0, ffloat); rc = ib_field_from_string(MM(), IB_S2SL("test_str"), "x", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NULSTR, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_nulstr_out(&fnulstr))); ASSERT_STREQ("x", fnulstr); rc = ib_field_from_string(MM(), IB_S2SL("test_str"), "-1.1x", &f); ASSERT_EQ(IB_OK, rc); ASSERT_TRUE(f); ASSERT_EQ(IB_FTYPE_NULSTR, f->type); ASSERT_EQ(IB_OK, ib_field_value(f, ib_ftype_nulstr_out(&fnulstr))); ASSERT_STREQ("-1.1x", fnulstr); }
/** * Do a larger integration test. */ TEST_F(CoreActionTest, integration) { ib_field_t *f; ib_num_t n; ASSERT_EQ(IB_OK, ib_data_get(ib_conn->tx->dpi, "r1", &f)); ASSERT_EQ(IB_FTYPE_NUM, f->type); ib_field_value(f, ib_ftype_num_out(&n)); ASSERT_EQ(1, n); ASSERT_EQ(IB_OK, ib_data_get(ib_conn->tx->dpi, "r2", &f)); ASSERT_EQ(IB_FTYPE_NUM, f->type); ib_field_value(f, ib_ftype_num_out(&n)); ASSERT_EQ(1, n); ASSERT_EQ(IB_OK, ib_data_get(ib_conn->tx->dpi, "r3", &f)); ASSERT_EQ(IB_FTYPE_NUM, f->type); ib_field_value(f, ib_ftype_num_out(&n)); ASSERT_EQ(1, n); ASSERT_EQ(IB_OK, ib_data_get(ib_conn->tx->dpi, "r4", &f)); ASSERT_EQ(IB_FTYPE_NUM, f->type); ib_field_value(f, ib_ftype_num_out(&n)); ASSERT_EQ(1, n); }
ib_status_t ib_cfgmap_get(ib_cfgmap_t *cm, const char *name, void *pval, ib_ftype_t *ptype) { IB_FTRACE_INIT(ib_cfgmap_get); ib_field_t *f; ib_status_t rc; rc = ib_hash_get(cm->hash, name, &f); if (rc != IB_OK) { if (ptype != NULL) { *ptype = IB_FTYPE_GENERIC; } IB_FTRACE_RET_STATUS(rc); } switch (f->type) { case IB_FTYPE_BYTESTR: *(ib_bytestr_t **)pval = ib_field_value_bytestr(f); ib_util_log_debug(4, "GET FIELD type=%d %" IB_BYTESTR_FMT "=\"%" IB_BYTESTR_FMT "\" (%p)", f->type, IB_BYTESTRSL_FMT_PARAM(f->name,f->nlen), IB_BYTESTR_FMT_PARAM(*(ib_bytestr_t **)pval), *(void **)pval); break; case IB_FTYPE_LIST: *(ib_list_t **)pval = ib_field_value_list(f); break; case IB_FTYPE_NULSTR: *(char **)pval = ib_field_value_nulstr(f); ib_util_log_debug(4, "GET FIELD type=%d %" IB_BYTESTR_FMT "=\"%s\" (%p)", f->type, IB_BYTESTRSL_FMT_PARAM(f->name,f->nlen), *(char **)pval, *(void **)pval); break; case IB_FTYPE_NUM: *(ib_num_t *)pval = *(ib_field_value_num(f)); ib_util_log_debug(4, "GET FIELD type=%d %" IB_BYTESTR_FMT "=%d (%p)", f->type, IB_BYTESTRSL_FMT_PARAM(f->name,f->nlen), *(int *)pval, *(void **)pval); break; case IB_FTYPE_UNUM: *(ib_unum_t *)pval = *(ib_field_value_unum(f)); ib_util_log_debug(4, "GET FIELD type=%d %" IB_BYTESTR_FMT "=%d (%p)", f->type, IB_BYTESTRSL_FMT_PARAM(f->name,f->nlen), *(unsigned int *)pval, *(void **)pval); break; case IB_FTYPE_GENERIC: default: *(void **)pval = ib_field_value(f); break; } if (ptype != NULL) { *ptype = f->type; } IB_FTRACE_RET_STATUS(IB_OK); }
ib_status_t ib_field_value_type( const ib_field_t *f, void *out_pval, ib_ftype_t t ) { ib_status_t rc; /* Compare the types */ if (f->type != t) { return IB_EINVAL; } /* Return the value as normal. */ rc = ib_field_value(f, out_pval); return rc; }
TEST_F(PcreModuleTest, test_match_capture_named) { ib_field_t *ib_field; const char *capname; const ib_bytestr_t *ib_bytestr; ib_status_t rc; /* Check :0 */ capname = ib_capture_fullname(ib_tx, "captest", 0); ASSERT_STREQ(capname, "captest:0"); ib_field = getTarget1(capname); ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field); ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type); /* Check :1 */ capname = ib_capture_fullname(ib_tx, "captest", 1); ASSERT_STREQ(capname, "captest:1"); ib_field = getTarget1(capname); ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field); ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type); /* Check :2 */ capname = ib_capture_fullname(ib_tx, "captest", 2); ASSERT_STREQ(capname, "captest:2"); ib_field = getTarget1(capname); ASSERT_NE(static_cast<ib_field_t*>(NULL), ib_field); ASSERT_EQ(static_cast<ib_ftype_t>(IB_FTYPE_BYTESTR), ib_field->type); rc = ib_field_value(ib_field, ib_ftype_bytestr_out(&ib_bytestr)); ASSERT_EQ(IB_OK, rc); /* Check that a value is over written correctly. */ ASSERT_EQ("4", std::string( reinterpret_cast<const char*>(ib_bytestr_const_ptr(ib_bytestr)), ib_bytestr_length(ib_bytestr) )); capname = ib_capture_fullname(ib_tx, "captest", 3); ASSERT_STREQ(capname, "captest:3"); ib_field = getTarget1(capname); ASSERT_FALSE(ib_field); }
ib_status_t ib_cfgmap_get(const ib_cfgmap_t *cm, const char *name, void *out_val, ib_ftype_t *ptype) { ib_field_t *f; ib_status_t rc; rc = ib_hash_get(cm->hash, &f, name); if (rc != IB_OK) { if (ptype != NULL) { *ptype = IB_FTYPE_GENERIC; } return rc; } if (ptype != NULL) { *ptype = f->type; } rc = ib_field_value(f, out_val); return rc; }
static ib_status_t xss_op_execute( ib_tx_t *tx, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *instance_data, void *cbdata ) { assert(tx != NULL); assert(field != NULL); assert(result != NULL); ib_bytestr_t *bs; ib_status_t rc; *result = 0; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field->type != IB_FTYPE_BYTESTR) { return IB_OK; } rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs)); if (rc != IB_OK) { return rc; } /* Run through libinjection. */ // TODO: flags parameter is currently undocumented - using 0 if (libinjection_is_xss((const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), 0)) { ib_log_debug_tx(tx, "Matched XSS."); *result = 1; } return IB_OK; }
/** * @brief Execute the rule. * * @param[in] ib Ironbee engine * @param[in] tx The transaction. * @param[in,out] User data. A @c pcre_rule_data_t. * @param[in] flags Operator instance flags * @param[in] field The field content. * @param[out] result The result. * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t dfa_operator_execute(ib_engine_t *ib, ib_tx_t *tx, const ib_rule_t *rule, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { IB_FTRACE_INIT(); assert(tx); assert(data); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; dfa_rule_data_t *rule_data; int *ovector; const char* subject; size_t subject_len; const ib_bytestr_t* bytestr; dfa_workspace_t *dfa_workspace; int options; /* dfa exec options. */ ovector = (int *)malloc(ovecsize*sizeof(*ovector)); if (ovector==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } /* Pull out the rule data. */ rule_data = (dfa_rule_data_t *)data; if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } subject_len = strlen(subject); } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } else { free(ovector); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Debug block. Escapes a string and prints it to the log. * Memory is freed. */ if (ib_log_get_level(ib) >= 9) { /* Worst case, we can have a string that is 4x larger. * Consider if a string of 0xF7 is passed. That single character * will expand to a string of 4 printed characters +1 for the \0 * character. */ char *debug_str = ib_util_hex_escape(subject, subject_len); if ( debug_str != NULL ) { ib_log_debug3_tx(tx, "Matching against: %s", debug_str); free( debug_str ); } } /* Get the per-tx workspace data for this rule data id. */ ib_rc = get_dfa_tx_data(tx, rule_data->id, &dfa_workspace); if (ib_rc == IB_ENOENT) { options = PCRE_PARTIAL_SOFT; ib_rc = alloc_dfa_tx_data(tx, rule_data->id, &dfa_workspace); if (ib_rc != IB_OK) { free(ovector); ib_log_error_tx(tx, "Unexpected error creating tx storage " "for dfa operator %s", rule_data->id); IB_FTRACE_RET_STATUS(ib_rc); } ib_log_debug_tx(tx, "Created DFA workspace at %p for id %s.", dfa_workspace, rule_data->id); } else if (ib_rc == IB_OK) { options = PCRE_PARTIAL_SOFT | PCRE_DFA_RESTART; ib_log_debug_tx(tx, "Reusing existing DFA workspace %p for id %s.", dfa_workspace, rule_data->id); } else { free(ovector); ib_log_error_tx(tx, "Unexpected error fetching dfa data " "for dfa operator %s", rule_data->id); IB_FTRACE_RET_STATUS(ib_rc); } /* Actually do the DFA match. */ matches = pcre_dfa_exec(rule_data->cpatt, rule_data->edata, subject, subject_len, 0, /* Starting offset. */ options, ovector, ovecsize, dfa_workspace->workspace, dfa_workspace->wscount); if (matches >= 0) { ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_PARTIAL) { ib_log_debug2_tx(tx, "Partial match found, but not a full match."); ib_rc = IB_OK; *result = 0; } else if (matches == PCRE_ERROR_NOMATCH) { if (ib_log_get_level(ib) >= 7) { char* tmp_c = malloc(subject_len+1); memcpy(tmp_c, subject, subject_len); tmp_c[subject_len] = '\0'; /* No match. Return false to the caller (*result = 0). */ ib_log_debug2_tx(tx, "No match for [%s] using pattern [%s].", tmp_c, rule_data->patt); free(tmp_c); } ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and report the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); IB_FTRACE_RET_STATUS(ib_rc); }
/** * @brief Execute the rule. * * @param[in] ib Ironbee engine * @param[in] tx The transaction. * @param[in,out] User data. A @c pcre_rule_data_t. * @param[in] flags Operator instance flags * @param[in] field The field content. * @param[out] result The result. * @returns IB_OK most times. IB_EALLOC when a memory allocation error handles. */ static ib_status_t pcre_operator_execute(ib_engine_t *ib, ib_tx_t *tx, const ib_rule_t *rule, void *data, ib_flags_t flags, ib_field_t *field, ib_num_t *result) { IB_FTRACE_INIT(); assert(ib!=NULL); assert(tx!=NULL); assert(tx->dpi!=NULL); assert(data!=NULL); int matches; ib_status_t ib_rc; const int ovecsize = 3 * MATCH_MAX; int *ovector = (int *)malloc(ovecsize*sizeof(*ovector)); const char* subject = NULL; size_t subject_len = 0; const ib_bytestr_t* bytestr; pcre_rule_data_t *rule_data = (pcre_rule_data_t *)data; pcre_extra *edata = NULL; #ifdef PCRE_JIT_STACK pcre_jit_stack *jit_stack = pcre_jit_stack_alloc(PCRE_JIT_MIN_STACK_SZ, PCRE_JIT_MAX_STACK_SZ); #endif if (ovector==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } if (field->type == IB_FTYPE_NULSTR) { ib_rc = ib_field_value(field, ib_ftype_nulstr_out(&subject)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } if (subject != NULL) { subject_len = strlen(subject); } } else if (field->type == IB_FTYPE_BYTESTR) { ib_rc = ib_field_value(field, ib_ftype_bytestr_out(&bytestr)); if (ib_rc != IB_OK) { free(ovector); IB_FTRACE_RET_STATUS(ib_rc); } if (bytestr != NULL) { subject_len = ib_bytestr_length(bytestr); subject = (const char *) ib_bytestr_const_ptr(bytestr); } } else { free(ovector); IB_FTRACE_RET_STATUS(IB_EINVAL); } if (subject == NULL) { subject = ""; } /* Debug block. Escapes a string and prints it to the log. * Memory is freed. */ if (ib_log_get_level(ib) >= 9) { /* Worst case, we can have a string that is 4x larger. * Consider if a string of 0xF7 is passed. That single character * will expand to a string of 4 printed characters +1 for the \0 * character. */ char *debug_str = ib_util_hex_escape(subject, subject_len); if ( debug_str != NULL ) { ib_log_debug3_tx(tx, "Matching against: %s", debug_str); free( debug_str ); } } #ifdef PCRE_JIT_STACK /* Log if we expected jit, but did not get it. */ if (rule_data->is_jit && jit_stack == NULL) { ib_log_debug(ib, "Failed to allocate a jit stack for a jit-compiled rule. " "Not using jit for this call."); edata = NULL; } /* If the study data is NULL or size zero, don't use it. */ else if (rule_data->edata == NULL || rule_data->study_data_sz <= 0) { edata = NULL; } /* Only if we get here do we use the study data (edata) in the rule_data. */ else { edata = rule_data->edata; pcre_assign_jit_stack(rule_data->edata, NULL, jit_stack); } #endif matches = pcre_exec(rule_data->cpatt, edata, subject, subject_len, 0, /* Starting offset. */ 0, /* Options. */ ovector, ovecsize); #ifdef PCRE_JIT_STACK if (jit_stack != NULL) { pcre_jit_stack_free(jit_stack); } #endif if (matches > 0) { if (ib_flags_all(rule->flags, IB_RULE_FLAG_CAPTURE) == true) { pcre_set_matches(ib, tx, ovector, matches, subject); } ib_rc = IB_OK; *result = 1; } else if (matches == PCRE_ERROR_NOMATCH) { if (ib_log_get_level(ib) >= 7) { char* tmp_c = malloc(subject_len+1); memcpy(tmp_c, subject, subject_len); tmp_c[subject_len] = '\0'; /* No match. Return false to the caller (*result = 0). */ ib_log_debug2_tx(tx, "No match for [%s] using pattern [%s].", tmp_c, rule_data->patt); free(tmp_c); } ib_rc = IB_OK; *result = 0; } else { /* Some other error occurred. Set the status to false and report the error. */ ib_rc = IB_EUNKNOWN; *result = 0; } free(ovector); IB_FTRACE_RET_STATUS(ib_rc); }
/** * Handle request_header events for remote IP extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "X-Forwarded-For" field. If found, the first value in the (comma * separated) list replaces the local ip address string in the connection * object. * * @param[in] ib IronBee object * @param[in,out] tx Transaction object * @param[in] event Event type * @param[in] cbdata Callback data (not used) * * @returns Status code */ static ib_status_t modua_remoteip(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *cbdata) { assert(ib != NULL); assert(tx != NULL); assert(tx->data != NULL); assert(event == request_header_finished_event); ib_field_t *field = NULL; ib_status_t rc = IB_OK; const ib_bytestr_t *bs; const uint8_t *data; size_t len; char *buf; uint8_t *comma; const ib_list_t *list; const ib_list_node_t *node; const ib_field_t *forwarded; uint8_t *stripped; size_t num; ib_flags_t flags; ib_log_debug3_tx(tx, "Checking for alternate remote address"); /* Extract the X-Forwarded-For from the provider instance */ rc = ib_data_get(tx->data, "request_headers:X-Forwarded-For", &field); if ( (field == NULL) || (rc != IB_OK) ) { ib_log_debug_tx(tx, "No X-Forwarded-For field"); return IB_OK; } /* Because we asked for a filtered item, what we get back is a list */ rc = ib_field_value(field, ib_ftype_list_out(&list)); if (rc != IB_OK) { ib_log_debug_tx(tx, "No request header collection"); return rc; } num = ib_list_elements(list); if (num == 0) { ib_log_debug_tx(tx, "No X-Forwarded-For header found"); return rc; } else if (num != 1) { ib_log_debug_tx(tx, "%zd X-Forwarded-For headers found: ignoring", num); return rc; } node = ib_list_last_const(list); if ( (node == NULL) || (node->data == NULL) ) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header found"); return rc; } forwarded = (const ib_field_t *)node->data; /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(forwarded, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_notice_tx(tx, "Invalid X-Forwarded-For header value"); return rc; } if (bs == NULL) { ib_log_notice_tx(tx, "X-Forwarded-For header not a bytestr"); return IB_EINVAL; } len = ib_bytestr_length(bs); data = ib_bytestr_const_ptr(bs); /* Search for a comma in the buffer */ comma = memchr(data, ',', len); if (comma != NULL) { len = comma - data; } /* Trim whitespace */ stripped = (uint8_t *)data; rc = ib_strtrim_lr_ex(IB_STROP_INPLACE, tx->mp, stripped, len, &stripped, &len, &flags); if (rc != IB_OK) { return rc; } /* Verify that it looks like a valid IP v4/6 address */ rc = ib_ip_validate_ex((const char *)stripped, len); if (rc != IB_OK) { ib_log_error_tx(tx, "X-Forwarded-For \"%.*s\" is not a valid IP address", (int)len, stripped ); return IB_OK; } /* Allocate memory for copy of stripped string */ buf = (char *)ib_mpool_alloc(tx->mp, len+1); if (buf == NULL) { ib_log_error_tx(tx, "Failed to allocate %zd bytes for remote address", len+1); return IB_EALLOC; } /* Copy the string out */ memcpy(buf, stripped, len); buf[len] = '\0'; ib_log_debug_tx(tx, "Remote address changed to \"%s\"", buf); /* This will lose the pointer to the original address * buffer, but it should be cleaned up with the rest * of the memory pool. */ tx->er_ipstr = buf; /* Update the remote address field in the tx collection */ rc = ib_data_add_bytestr(tx->data, "remote_addr", (uint8_t*)buf, len, NULL); if (rc != IB_OK) { ib_log_error_tx(tx, "Failed to create remote address TX field: %s", ib_status_to_string(rc)); return rc; } return IB_OK; }
/** * String modification transformation core * * @param[in] mp Memory pool to use for allocations. * @param[in] str_fn NUL-terminated string transformation function * @param[in] ex_fn EX (string/length) transformation function * @param[in] fin Input field. * @param[out] fout Output field. This is NULL on error. * * @returns IB_OK if successful. */ static ib_status_t tfn_strmod(ib_mpool_t *mp, ib_strmod_fn_t str_fn, ib_strmod_ex_fn_t ex_fn, const ib_field_t *fin, const ib_field_t **fout) { ib_status_t rc; ib_flags_t result; ib_field_t *fnew; assert(mp != NULL); assert(str_fn != NULL); assert(ex_fn != NULL); assert(fin != NULL); assert(fout != NULL); /* Initialize the output field pointer */ *fout = NULL; switch(fin->type) { case IB_FTYPE_NULSTR : { const char *in; char *out; rc = ib_field_value(fin, ib_ftype_nulstr_out(&in)); if (rc != IB_OK) { return rc; } if (in == NULL) { return IB_EINVAL; } rc = str_fn(IB_STROP_COW, mp, (char *)in, &out, &result); if (rc != IB_OK) { return rc; } rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_NULSTR, ib_ftype_nulstr_in(out)); if (rc != IB_OK) { return rc; } *fout = fnew; break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; const uint8_t *din; uint8_t *dout; size_t dlen; rc = ib_field_value(fin, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { return rc; } if (bs == NULL) { return IB_EINVAL; } din = ib_bytestr_const_ptr(bs); if (din == NULL) { return IB_EINVAL; } dlen = ib_bytestr_length(bs); rc = ex_fn(IB_STROP_COW, mp, (uint8_t *)din, dlen, &dout, &dlen, &result); if (rc != IB_OK) { return rc; } rc = ib_field_create_bytestr_alias(&fnew, mp, fin->name, fin->nlen, dout, dlen); if (rc != IB_OK) { return rc; } *fout = fnew; break; } default: return IB_EINVAL; } /* switch(fin->type) */ return IB_OK; }
/** * Length transformation * * @param[in] mp Memory pool to use for allocations. * @param[in] fin Input field. * @param[out] fout Output field. This is NULL on error. * @param[in] fndata Callback data * * @returns IB_OK if successful. */ static ib_status_t tfn_length(ib_mpool_t *mp, const ib_field_t *fin, const ib_field_t **fout, void *fndata) { assert(mp != NULL); assert(fin != NULL); assert(fout != NULL); ib_status_t rc = IB_OK; ib_field_t *fnew; /* Initialize the output field pointer */ *fout = NULL; /** * This works on C-style (NUL terminated) and byte strings. Note * that data is assumed to be a NUL terminated string (because our * configuration parser can't produce anything else). **/ if (fin->type == IB_FTYPE_NULSTR) { const char *fval; rc = ib_field_value(fin, ib_ftype_nulstr_out(&fval)); if (rc != IB_OK) { return rc; } const ib_num_t len = strlen(fval); rc = ib_field_create( &fnew, mp, IB_FIELD_NAME("Length"), IB_FTYPE_NUM, ib_ftype_num_in(&len) ); } else if (fin->type == IB_FTYPE_BYTESTR) { const ib_bytestr_t *value; rc = ib_field_value(fin, ib_ftype_bytestr_out(&value)); if (rc != IB_OK) { return rc; } const ib_num_t len = ib_bytestr_length(value); rc = ib_field_create( &fnew, mp, IB_FIELD_NAME("Length"), IB_FTYPE_NUM, ib_ftype_num_in(&len) ); } else if (fin->type == IB_FTYPE_LIST) { const ib_list_node_t *node = NULL; const ib_list_t *ilist; /** Incoming list */ /* Get the incoming list */ // @todo Remove mutable once list is const correct. rc = ib_field_value(fin, ib_ftype_list_out(&ilist)); if (rc != IB_OK) { return rc; } if (ilist == NULL) { return IB_EUNKNOWN; } /* Create the outgoing list field */ rc = ib_field_create( &fnew, mp, IB_FIELD_NAME("Length"), IB_FTYPE_LIST, NULL ); if (rc != IB_OK) { return rc; } /* Walk through the incoming fields */ IB_LIST_LOOP_CONST(ilist, node) { const ib_field_t *ifield = (ib_field_t *)node->data; const ib_field_t *ofield = NULL; rc = tfn_length(mp, ifield, &ofield, NULL); if (rc != IB_OK) { return rc; } rc = ib_field_list_add_const(fnew, ofield); if (rc != IB_OK) { return rc; } } } else {
const char *ib_field_format( const ib_field_t *field, bool quote, bool escape, const char **type_name, char *buf, size_t bufsize ) { ib_status_t rc; const char *tname = NULL; assert(buf != NULL); assert(bufsize > 0); *buf = '\0'; if (field == NULL) { tname = "NULL"; if (quote) { strncpy(buf, "\"\"", bufsize-1); *(buf+bufsize) = '\0'; } else { *buf = '\0'; } } else { switch (field->type) { case IB_FTYPE_NULSTR : { const char *s; tname = "NULSTR"; rc = ib_field_value(field, ib_ftype_nulstr_out(&s)); if (rc != IB_OK) { break; } if (escape) { ib_string_escape_json_buf(s, quote, buf, bufsize, NULL, NULL); } else if (quote) { snprintf(buf, bufsize, "\"%s\"", (s?s:"")); } else { strncpy(buf, s, bufsize-1); *(buf+bufsize-1) = '\0'; } break; } case IB_FTYPE_BYTESTR: { const ib_bytestr_t *bs; tname = "BYTESTR"; rc = ib_field_value(field, ib_ftype_bytestr_out(&bs)); if (rc != IB_OK) { break; } if (escape) { ib_string_escape_json_buf_ex(ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), true, quote, buf, bufsize, NULL, NULL); } else if (quote) { snprintf(buf, bufsize, "\"%.*s\"", (int)ib_bytestr_length(bs), (const char *)ib_bytestr_const_ptr(bs)); } else { size_t len = ib_bytestr_length(bs); if (len > (bufsize - 1) ) { len = bufsize - 1; } strncpy(buf, (const char *)ib_bytestr_const_ptr(bs), len); *(buf+len) = '\0'; } break; } case IB_FTYPE_NUM : /**< Numeric value */ { ib_num_t n; tname = "NUM"; rc = ib_field_value(field, ib_ftype_num_out(&n)); if (rc != IB_OK) { break; } snprintf(buf, bufsize, "%"PRId64, n); break; } case IB_FTYPE_FLOAT : /**< Float numeric value */ { ib_float_t f; tname = "FLOAT"; rc = ib_field_value(field, ib_ftype_float_out(&f)); if (rc != IB_OK) { break; } snprintf(buf, bufsize, "%Lf", f); break; } case IB_FTYPE_LIST : /**< List */ { const ib_list_t *lst; size_t len; tname = "LIST"; rc = ib_field_value(field, ib_ftype_list_out(&lst)); if (rc != IB_OK) { break; } len = IB_LIST_ELEMENTS(lst); if (len == 0) { snprintf(buf, bufsize, "list[%zd]", len); } else { const ib_list_node_t *node; node = ib_list_last_const(lst); if (node == NULL) { snprintf(buf, bufsize, "list[%zd]", len); } else { ib_field_format((const ib_field_t *)node->data, quote, escape, &tname, buf, bufsize); } } break; } default: tname = buf; snprintf(buf, bufsize, "type = %d", field->type); break; } } /* Store the type name */ if (type_name != NULL) { *type_name = tname; } /* Return the buffer */ return buf; }
ib_status_t ib_tfn_execute( ib_mpool_t *mp, const ib_tfn_t *tfn, const ib_field_t *fin, const ib_field_t **fout ) { assert(mp != NULL); assert(tfn != NULL); assert(fin != NULL); assert(fout != NULL); ib_status_t rc; const ib_field_t *out = NULL; if (fin->type == IB_FTYPE_LIST && ! ib_tfn_handle_list(tfn)) { /* Unroll list */ const ib_list_t *value_list; const ib_list_node_t *node; ib_list_t *out_list; ib_field_t *fnew; rc = ib_field_value(fin, ib_ftype_list_out(&value_list)); if (rc != IB_OK) { return rc; } rc = ib_list_create(&out_list, mp); if (rc != IB_OK) { return rc; } IB_LIST_LOOP_CONST(value_list, node) { const ib_field_t *in; const ib_field_t *tfn_out; in = (const ib_field_t *)ib_list_node_data_const(node); assert(in != NULL); rc = ib_tfn_execute(mp, tfn, in, &tfn_out); if (rc != IB_OK) { return rc; } if (tfn_out == NULL) { return IB_EINVAL; } rc = ib_list_push(out_list, (void *)tfn_out); if (rc != IB_OK) { return rc; } } /* Finally, create the output field (list) and return it */ rc = ib_field_create(&fnew, mp, fin->name, fin->nlen, IB_FTYPE_LIST, ib_ftype_list_in(out_list)); if (rc != IB_OK) { return rc; } out = fnew; } else {