// 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); }
/** * Handle request_header events for user agent extraction. * * Extract the "request_headers" field (a list) from the transactions's * data provider instance, then loop through the list, looking for the * "User-Agent" field. If found, the value is parsed and used to update the * connection object fields. * * @param[in] ib IronBee object * @param[in,out] tx Transaction. * @param[in] event Event type * @param[in] data Callback data (not used) * * @returns Status code */ static ib_status_t modua_user_agent(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *data) { assert(ib != NULL); assert(tx != NULL); assert(tx->data != NULL); assert(event == request_header_finished_event); ib_field_t *req_agent = NULL; ib_status_t rc = IB_OK; const ib_list_t *bs_list; const ib_bytestr_t *bs; /* Extract the User-Agent header field from the provider instance */ rc = ib_data_get(tx->data, "request_headers:User-Agent", &req_agent); if ( (req_agent == NULL) || (rc != IB_OK) ) { ib_log_debug_tx(tx, "request_header_finished_event: No user agent"); return IB_OK; } if (req_agent->type != IB_FTYPE_LIST) { ib_log_error_tx(tx, "Expected request_headers:User-Agent to " "return list of values."); return IB_EINVAL; } rc = ib_field_value_type(req_agent, ib_ftype_list_out(&bs_list), IB_FTYPE_LIST); if (rc != IB_OK) { ib_log_error_tx(tx, "Cannot retrieve request_headers:User-Agent: %d", rc); return rc; } if (IB_LIST_ELEMENTS(bs_list) == 0) { ib_log_debug_tx(tx, "request_header_finished_event: No user agent"); return IB_OK; } req_agent = (ib_field_t *)IB_LIST_NODE_DATA(IB_LIST_LAST(bs_list)); /* Found it: copy the data into a newly allocated string buffer */ rc = ib_field_value_type(req_agent, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR); if (rc != IB_OK) { ib_log_error_tx(tx, "Request user agent is not a BYTESTR: %s", ib_status_to_string(rc)); return rc; } /* Finally, split it up & store the components */ rc = modua_agent_fields(ib, tx, bs); return rc; }
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(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); }
/** * 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); }
TEST(TestIronBee, test_data_name) { ib_engine_t *ib = NULL; ib_data_t *data = NULL; ib_field_t *list_field = NULL; ib_field_t *out_field = NULL; ibtest_engine_create(&ib); ASSERT_EQ(IB_OK, ib_data_create(ib_engine_pool_main_get(ib), &data)); ASSERT_TRUE(data); ASSERT_IB_OK(ib_data_add_list(data, "ARGV", &list_field)); ASSERT_IB_OK(ib_data_get(data, "ARGV", &out_field)); ASSERT_TRUE(out_field); out_field = NULL; ASSERT_IB_OK(ib_data_get_ex(data, "ARGV:/.*(1|3)/", 4, &out_field)); ASSERT_TRUE(out_field); ibtest_engine_destroy(ib); }
//! Ensure that the given field name exists in tx->dpi. static ib_status_t ensure_field_exists(ib_engine_t *ib, ib_tx_t *tx, const char *field_name) { IB_FTRACE_INIT(); ib_status_t rc; assert(ib!=NULL); assert(tx!=NULL); assert(tx->dpi!=NULL); assert(field_name!=NULL); ib_field_t *ib_field; rc = ib_data_get(tx->dpi, field_name, &ib_field); if (rc == IB_ENOENT) { ib_data_add_list(tx->dpi, field_name, NULL); } IB_FTRACE_RET_STATUS(IB_OK); }
/** * 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; }
/// @test Test ironbee library - data provider TEST(TestIronBee, test_data_dynf) { ib_engine_t *ib; ib_data_config_t *dataconfig; ib_data_t *data; ib_field_t *dynf; ib_field_t *f; ib_field_t *f2; ib_status_t rc; ib_num_t n; ib_list_t* l; 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); /* Create a field with no initial value. */ ASSERT_EQ( IB_OK, ib_field_create_dynamic( &dynf, ib_engine_pool_main_get(ib), IB_FIELD_NAME("test_dynf"), IB_FTYPE_LIST, dyn_get, (void *)ib_engine_pool_main_get(ib), NULL, NULL ) ); ASSERT_TRUE(dynf); ASSERT_EQ(9UL, dynf->nlen); ASSERT_MEMEQ("test_dynf", dynf->name, 9); /* Add the field to the data store. */ ASSERT_EQ(IB_OK, ib_data_add(data, dynf)); /* Fetch the field from the data store */ ASSERT_EQ(IB_OK, ib_data_get(data, "test_dynf", &f)); ASSERT_TRUE(f); ASSERT_EQ(dynf, f); /* Fetch a dynamic field from the data store */ ASSERT_EQ(IB_OK, ib_data_get(data, "test_dynf:dyn_subkey", &f)); ASSERT_TRUE(f); ASSERT_EQ(9UL, f->nlen); /* Get the list value from the dynamic field. */ rc = ib_field_mutable_value(f, ib_ftype_list_mutable_out(&l)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(1UL, ib_list_elements(l)); /* Get the single value from the list. */ f2 = (ib_field_t *)ib_list_node_data(ib_list_first(l)); ASSERT_TRUE(f2); ASSERT_EQ(10UL, f2->nlen); rc = ib_field_value(f2, ib_ftype_num_out(&n)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(5, n); /* Fetch a another subkey */ ASSERT_EQ(IB_OK, ib_data_get(data, "test_dynf:dyn_subkey2", &f)); ASSERT_TRUE(f); ASSERT_EQ(9UL, f->nlen); /* Get the list value from the dynamic field. */ rc = ib_field_mutable_value(f, ib_ftype_list_mutable_out(&l)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(1UL, ib_list_elements(l)); /* Get the single value from the list. */ f2 = (ib_field_t *)ib_list_node_data(ib_list_first(l)); ASSERT_TRUE(f2); ASSERT_EQ(11UL, f2->nlen); rc = ib_field_value(f2, ib_ftype_num_out(&n)); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(5, n); ibtest_engine_destroy(ib); }
/** * @internal * Handle signature execution. * * @param ib Engine * @param tx Transaction * @param cbdata Phase passed as pointer value * * @return Status code */ static ib_status_t pocsig_handle_sigs(ib_engine_t *ib, ib_tx_t *tx, void *cbdata) { IB_FTRACE_INIT(pocsig_handle_post); pocsig_cfg_t *cfg; pocsig_phase_t phase = (pocsig_phase_t)(uintptr_t)cbdata; ib_list_t *sigs; ib_list_node_t *node; int dbglvl; ib_status_t rc; /* Get the pocsig configuration for this context. */ rc = ib_context_module_config(tx->ctx, IB_MODULE_STRUCT_PTR, (void *)&cfg); if (rc != IB_OK) { ib_log_error(ib, 1, "Failed to fetch %s config: %d", MODULE_NAME_STR, rc); } /* If tracing is enabled, lower the log level. */ dbglvl = cfg->trace ? 4 : 9; /* Get the list of sigs for this phase. */ sigs = cfg->phase[phase]; if (sigs == NULL) { ib_log_debug(ib, dbglvl, "No signatures for phase=%d ctx=%p", phase, tx->ctx); IB_FTRACE_RET_STATUS(IB_OK); } ib_log_debug(ib, dbglvl, "Executing %d signatures for phase=%d ctx=%p", ib_list_elements(sigs), phase, tx->ctx); /* Run all the sigs for this phase. */ IB_LIST_LOOP(sigs, node) { pocsig_sig_t *s = (pocsig_sig_t *)ib_list_node_data(node); ib_field_t *f; /* Fetch the field. */ rc = ib_data_get(tx->dpi, s->target, &f); if (rc != IB_OK) { ib_log_error(ib, 4, "PocSig: No field named \"%s\"", s->target); continue; } /* Perform the match. */ ib_log_debug(ib, dbglvl, "PocSig: Matching \"%s\" against field \"%s\"", s->patt, s->target); rc = ib_matcher_match_field(cfg->pcre, s->cpatt, 0, f, NULL); if (rc == IB_OK) { ib_logevent_t *e; ib_log_debug(ib, dbglvl, "PocSig MATCH: %s at %s", s->patt, s->target); /* Create the event. */ rc = ib_logevent_create( &e, tx->mp, "-", IB_LEVENT_TYPE_ALERT, IB_LEVENT_ACT_UNKNOWN, IB_LEVENT_PCLASS_UNKNOWN, IB_LEVENT_SCLASS_UNKNOWN, 90, 80, IB_LEVENT_SYS_UNKNOWN, IB_LEVENT_ACTION_IGNORE, IB_LEVENT_ACTION_IGNORE, s->emsg ); if (rc != IB_OK) { ib_log_error(ib, 3, "PocSig: Error generating event: %d", rc); continue; } /* Log the event. */ ib_clog_event(tx->ctx, e); } else { ib_log_debug(ib, dbglvl, "PocSig NOMATCH"); } }
/* * Callback used to generate request header fields. */ static ib_status_t core_gen_request_header_fields(ib_engine_t *ib, ib_tx_t *tx, ib_state_event_type_t event, void *cbdata) { ib_field_t *f; ib_status_t rc; assert(ib != NULL); assert(tx != NULL); assert(event == request_header_finished_event); /** * Alias connection remote and server addresses */ rc = ib_data_get(tx->conn->data, "server_addr", &f); if (rc != IB_OK) { return rc; } rc = ib_data_add(tx->data, f); if (rc != IB_OK) { return rc; } rc = ib_data_get(tx->conn->data, "server_port", &f); if (rc != IB_OK) { return rc; } rc = ib_data_add(tx->data, f); if (rc != IB_OK) { return rc; } rc = ib_data_get(tx->conn->data, "remote_addr", &f); if (rc != IB_OK) { return rc; } rc = ib_data_add(tx->data, f); if (rc != IB_OK) { return rc; } rc = ib_data_get(tx->conn->data, "remote_port", &f); if (rc != IB_OK) { return rc; } rc = ib_data_add(tx->data, f); if (rc != IB_OK) { return rc; } core_gen_tx_numeric_field(tx, "conn_tx_count", tx->conn->tx_count); if (tx->request_line != NULL) { core_gen_tx_bytestr_alias_field(tx, "request_line", tx->request_line->raw); core_gen_tx_bytestr_alias_field(tx, "request_method", tx->request_line->method); core_gen_tx_bytestr_alias_field(tx, "request_uri_raw", tx->request_line->uri); core_gen_tx_bytestr_alias_field(tx, "request_protocol", tx->request_line->protocol); } /* Populate the ARGS collection. */ rc = ib_data_get(tx->data, "ARGS", &f); if (rc == IB_OK) { ib_field_t *param_list; /* Add request URI parameters to ARGS collection. */ rc = ib_data_get(tx->data, "request_uri_params", ¶m_list); if (rc == IB_OK) { ib_list_t *field_list; ib_list_node_t *node = NULL; rc = ib_field_mutable_value( param_list, ib_ftype_list_mutable_out(&field_list) ); if (rc != IB_OK) { return rc; } IB_LIST_LOOP(field_list, node) { ib_field_t *param = (ib_field_t *)ib_list_node_data(node); /* Add the field to the ARGS collection. */ rc = ib_field_list_add(f, param); if (rc != IB_OK) { ib_log_notice_tx(tx, "Failed to add parameter to " "ARGS collection: %s", ib_status_to_string(rc)); } }
/** * Create an alias list collection. * * @param ib Engine. * @param tx Transaction. * @param name Collection name * @param header Header list to alias * * @returns Status code */ static ib_status_t create_header_alias_list( ib_engine_t *ib, ib_tx_t *tx, const char *name, ib_parsed_header_wrapper_t *header) { ib_field_t *f; ib_list_t *header_list; ib_status_t rc; ib_parsed_name_value_pair_list_t *nvpair; assert(ib != NULL); assert(tx != NULL); assert(name != NULL); assert(header != NULL); /* Create the list */ rc = ib_data_get(tx->data, name, &f); if (rc == IB_ENOENT) { rc = ib_data_add_list(tx->data, name, &f); if (rc != IB_OK) { return rc; } } else if (rc != IB_OK) { return rc; } rc = ib_field_mutable_value(f, ib_ftype_list_mutable_out(&header_list)); if (rc != IB_OK) { return rc; } /* Loop through the list & alias everything */ for(nvpair = header->head; nvpair != NULL; nvpair = nvpair->next) { assert(nvpair); assert(nvpair->value); ib_bytestr_t *bs = NULL; if (ib_bytestr_ptr(nvpair->value) != NULL) { rc = ib_bytestr_alias_mem( &bs, tx->mp, ib_bytestr_ptr(nvpair->value), ib_bytestr_length(nvpair->value) ); } else { rc = ib_bytestr_dup_mem(&bs, tx->mp, (const uint8_t *)"", 0); } if (rc != IB_OK) { ib_log_error_tx( tx, "Error creating bytestring of '%.*s' for %s: %s", (int)ib_bytestr_length(nvpair->name), (const char *)ib_bytestr_ptr(nvpair->name), name, ib_status_to_string(rc) ); return rc; } /* Create a byte string field */ rc = ib_field_create( &f, tx->mp, (const char *)ib_bytestr_const_ptr(nvpair->name), ib_bytestr_length(nvpair->name), IB_FTYPE_BYTESTR, ib_ftype_bytestr_in(bs) ); if (rc != IB_OK) { ib_log_error_tx(tx, "Error creating field of '%.*s' for %s: %s", (int)ib_bytestr_length(nvpair->name), (const char *)ib_bytestr_ptr(nvpair->name), name, ib_status_to_string(rc)); return rc; } /* Add the field to the list */ rc = ib_list_push(header_list, f); if (rc != IB_OK) { ib_log_error_tx(tx, "Error adding alias of '%.*s' to %s list: %s", (int)ib_bytestr_length(nvpair->name), (const char *)ib_bytestr_ptr(nvpair->name), name, ib_status_to_string(rc)); return rc; } } return IB_OK; }
// FIXME: This needs to go away and be replaced with dynamic fields static ib_status_t core_gen_placeholder_fields(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 == tx_started_event); ib_status_t rc; ib_field_t *tmp; /* Core Request Fields */ rc = core_field_placeholder_bytestr(tx->data, "request_line"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_method"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_protocol"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_raw"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_scheme"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_username"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_password"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_host"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_host"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_port"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_path"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_path_raw"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_query"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_uri_fragment"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_content_type"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "request_filename"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "auth_type"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "auth_username"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "auth_password"); if (rc != IB_OK) { return rc; } /* Core Request Collections */ rc = ib_data_add_list(tx->data, "request_headers", NULL); if (rc != IB_OK) { return rc; } rc = ib_data_add_list(tx->data, "request_cookies", NULL); if (rc != IB_OK) { return rc; } rc = ib_data_add_list(tx->data, "request_uri_params", NULL); if (rc != IB_OK) { return rc; } rc = ib_data_add_list(tx->data, "request_body_params", NULL); if (rc != IB_OK) { return rc; } /* ARGS collection */ rc = ib_data_get(tx->data, "ARGS", &tmp); if (rc == IB_ENOENT) { rc = ib_data_add_list(tx->data, "ARGS", NULL); if (rc != IB_OK) { return rc; } } else if (rc != IB_OK) { return rc; } /* Flags collection */ rc = ib_data_get(tx->data, "FLAGS", &tmp); if (rc == IB_ENOENT) { rc = ib_data_add_list(tx->data, "FLAGS", NULL); if (rc != IB_OK) { return rc; } } else if (rc != IB_OK) { return rc; } /* Initialize CAPTURE */ { ib_field_t *capture; rc = ib_capture_acquire(tx, NULL, &capture); if (rc != IB_OK) { return rc; } assert(capture != NULL); rc = ib_capture_clear(capture); if (rc != IB_OK) { return rc; } } /* Core Response Fields */ rc = core_field_placeholder_bytestr(tx->data, "response_line"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "response_protocol"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "response_status"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "response_message"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "response_content_type"); if (rc != IB_OK) { return rc; } /* Core Response Collections */ rc = ib_data_add_list(tx->data, "response_headers", NULL); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "FIELD_NAME"); if (rc != IB_OK) { return rc; } rc = core_field_placeholder_bytestr(tx->data, "FIELD_NAME_FULL"); if (rc != IB_OK) { return rc; } rc = ib_data_add_list(tx->data, "response_cookies", NULL); return rc; }
/** * Set the matches into the given field name as .0, .1, .2 ... .9. * * @param[in] ib The IronBee engine to log to. * @param[in] tx The transaction to store the values into (tx->dpi). * @param[in] field_name The field to populate with Regex matches. * @param[in] ovector The vector of integer pairs of matches from PCRE. * @param[in] matches The number of matches. * @param[in] subject The matched-against string data. * * @returns IB_OK or IB_EALLOC. */ static ib_status_t pcre_set_matches(ib_engine_t *ib, ib_tx_t *tx, const char* field_name, int *ovector, int matches, const char *subject) { IB_FTRACE_INIT(); /* IronBee status. */ ib_status_t rc; /* Iterator. */ int i; /* Length of field_name. */ const int field_name_sz = strlen(field_name); /* The length of the match. */ size_t match_len; /* The first character in the match. */ const char* match_start; /* +3 = '.', [digit], and \0. */ char *full_field_name = malloc(field_name_sz+3); /* Holder to build an optional debug message in. */ char *debug_msg; /* Holder for a copy of the field value when creating a new field. */ ib_bytestr_t *field_value; /* Field holder. */ ib_field_t *ib_field; /* Ensure the above allocations happened. */ if (full_field_name==NULL) { IB_FTRACE_RET_STATUS(IB_EALLOC); } rc = ensure_field_exists(ib, tx, field_name); if (rc != IB_OK) { ib_log_alert_tx(tx, "Could not ensure that field %s was a list.", field_name); free(full_field_name); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* We have a match! Now populate TX.0-9 in tx->dpi. */ for (i=0; i<matches; i++) { /* Build the field name. Typically TX.0, TX.1 ... TX.9 */ sprintf(full_field_name, "%s.%d", field_name, i); /* Readability. Mark the start and length of the string. */ match_start = subject+ovector[i*2]; match_len = ovector[i*2+1] - ovector[i*2]; /* If debugging this, copy the string value out and print it to the * log. This could be dangerous as there could be non-character * values in the match. */ if (ib_log_get_level(ib) >= 7) { debug_msg = malloc(match_len+1); /* Notice: Don't provoke a crash if malloc fails. */ if (debug_msg != NULL) { memcpy(debug_msg, match_start, match_len); debug_msg[match_len] = '\0'; ib_log_debug2_tx(tx, "REGEX Setting %s=%s", full_field_name, debug_msg); free(debug_msg); } } ib_data_get(tx->dpi, full_field_name, &ib_field); if (ib_field == NULL) { ib_data_add_bytestr(tx->dpi, full_field_name, (uint8_t*)subject+ovector[i*2], match_len, NULL); } else { ib_bytestr_dup_mem(&field_value, tx->mp, (const uint8_t*)match_start, match_len); ib_field_setv_no_copy( ib_field, ib_ftype_bytestr_mutable_in(field_value) ); } } IB_FTRACE_RET_STATUS(IB_OK); }
/** * Feed a collection of byte strings from an @ref ib_data_t to automata. * * @param[in] ib IronBee engine; used for logging. * @param[in] eudoxus Eudoxus engine; used for ia_eudoxus_error(). * @param[in] state Current Eudoxus execution state; updated. * @param[in] data Data source. * @param[in] collection Collection to feed. * @return * - IB_OK on success. * - IB_EINVAL on IronAutomata failure; will emit log message. * - IB_EOTHER on IronBee failure; will emit log message. */ static ib_status_t fast_feed_data_collection( const ib_engine_t *ib, const ia_eudoxus_t *eudoxus, ia_eudoxus_state_t *state, const ib_data_t *data, const fast_collection_spec_t *collection ) { assert(ib != NULL); assert(eudoxus != NULL); assert(state != NULL); assert(data != NULL); assert(collection != NULL); ib_field_t *field; const ib_list_t *subfields; const ib_list_node_t *node; const ib_field_t *subfield; const ib_bytestr_t *bs; ib_status_t rc; rc = ib_data_get(data, collection->name, &field); if (rc == IB_ENOENT) { ib_log_error( ib, "fast: No such data %s", collection->name ); return IB_EOTHER; } else if (rc != IB_OK) { ib_log_error( ib, "fast: Error fetching data %s: %s", collection->name, ib_status_to_string(rc) ); return IB_EOTHER; } rc = ib_field_value_type( field, ib_ftype_list_out(&subfields), IB_FTYPE_LIST ); if (rc != IB_OK) { ib_log_error( ib, "fast: Error loading data field %s: %s", collection->name, ib_status_to_string(rc) ); return IB_EOTHER; } IB_LIST_LOOP_CONST(subfields, node) { subfield = (const ib_field_t *)ib_list_node_data_const(node); assert(subfield != NULL); rc = ib_field_value_type( subfield, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR ); if (rc != IB_OK) { ib_log_error( ib, "fast: Error loading data subfield %s of %s: %s", subfield->name, collection->name, ib_status_to_string(rc) ); return IB_EOTHER; } rc = fast_feed( ib, eudoxus, state, (const uint8_t *)subfield->name, subfield->nlen ); if (rc != IB_OK) { return rc; } rc = fast_feed( ib, eudoxus, state, (const uint8_t *)collection->separator, strlen(collection->separator) ); if (rc != IB_OK) { return rc; } if (ib_bytestr_const_ptr(bs) != NULL && ib_bytestr_size(bs) > 0) { rc = fast_feed( ib, eudoxus, state, ib_bytestr_const_ptr(bs), ib_bytestr_size(bs) ); if (rc != IB_OK) { return rc; } } rc = fast_feed( ib, eudoxus, state, (const uint8_t *)c_data_separator, strlen(c_data_separator) ); if (rc != IB_OK) { return rc; } }
/** * Feed a byte string from an @ref ib_data_t to the automata. * * @param[in] ib IronBee engine; used for logging. * @param[in] eudoxus Eudoxus engine; used for * ia_eudoxus_error(). * @param[in] state Current Eudoxus execution state; updated. * @param[in] data Data source. * @param[in] bytestring_field_name Name of data field to feed. * @return * - IB_OK on success. * - IB_EINVAL on IronAutomata failure; will emit log message. * - IB_EOTHER on IronBee failure; will emit log message. */ static ib_status_t fast_feed_data_bytestring( const ib_engine_t *ib, const ia_eudoxus_t *eudoxus, ia_eudoxus_state_t *state, const ib_data_t *data, const char *bytestring_field_name ) { assert(ib != NULL); assert(eudoxus != NULL); assert(state != NULL); assert(data != NULL); assert(bytestring_field_name != NULL); ib_field_t *field; const ib_bytestr_t *bs; ib_status_t rc; rc = ib_data_get(data, bytestring_field_name, &field); if (rc == IB_ENOENT) { ib_log_error( ib, "fast: No such data %s", bytestring_field_name ); return IB_EOTHER; } else if (rc != IB_OK) { ib_log_error( ib, "fast: Error fetching data %s: %s", bytestring_field_name, ib_status_to_string(rc) ); return IB_EOTHER; } rc = ib_field_value_type( field, ib_ftype_bytestr_out(&bs), IB_FTYPE_BYTESTR ); if (rc != IB_OK) { ib_log_error( ib, "fast: Error loading data field %s: %s", bytestring_field_name, ib_status_to_string(rc) ); return IB_EOTHER; } if (ib_bytestr_const_ptr(bs) == NULL || ib_bytestr_size(bs) == 0) { return IB_OK; } return fast_feed( ib, eudoxus, state, ib_bytestr_const_ptr(bs), ib_bytestr_size(bs) ); }