Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
0
/**
 * 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 (module)
 *
 * @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->var_store != NULL);
    assert(event == request_header_finished_event);

    const ib_module_t    *m = (const ib_module_t *)cbdata;
    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;
    const modua_config_t *cfg;

    rc = ib_context_module_config(ib_context_main(ib), m, &cfg);
    if (rc != IB_OK) {
        ib_log_error_tx(tx, "Can't fetch configuration: %s",
                        ib_status_to_string(rc));
        return rc;
    }

    ib_log_debug3_tx(tx, "Checking for alternate remote address");

    /* Extract the X-Forwarded-For header field */
    rc = ib_var_target_get_const(
        cfg->forwarded_for,
        &list,
        tx->mp,
        tx->var_store
    );
    if (rc == IB_ENOENT || ib_list_elements(list) == 0) {
        ib_log_debug_tx(tx, "No X-Forwarded-For");
        return IB_OK;
    }
    if (rc != IB_OK) {
        ib_log_error_tx(tx,
                        "Cannot retrieve request_headers:User-Agent: %d",
                        rc);
        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_field_create_bytestr_alias(
        &field,
        tx->mp,
        "", 0,
        (uint8_t *)buf, len
    );
    if (rc != IB_OK) {
        ib_log_error_tx(tx, "Failed to create field for remote_addr: %s",
                        ib_status_to_string(rc));
        return rc;
    }
    rc = ib_var_source_set(cfg->remote_addr, tx->var_store, field);
    if (rc != IB_OK) {
        ib_log_error_tx(tx,
                        "Failed to set remote address var: %s",
                        ib_status_to_string(rc));
        return rc;
    }

    return IB_OK;
}
Beispiel #4
0
/**
 * 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 (module)
 *
 * @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->var_store != NULL);
    assert(event == request_header_finished_event);
    assert(data != NULL);

    const ib_module_t *m = (const ib_module_t *)data;
    const ib_field_t  *req_agent = NULL;
    ib_status_t         rc = IB_OK;
    const ib_list_t *bs_list;
    const ib_bytestr_t *bs;
    const modua_config_t *cfg;

    rc = ib_context_module_config(ib_context_main(ib), m, &cfg);
    if (rc != IB_OK) {
        ib_log_error_tx(tx, "Can't fetch configuration: %s",
                        ib_status_to_string(rc));
        return rc;
    }

    /* Extract the User-Agent header field */
    rc = ib_var_target_get_const(
        cfg->user_agent,
        &bs_list,
        tx->mp,
        tx->var_store
    );
    if (rc == IB_ENOENT || ib_list_elements(bs_list) == 0) {
        ib_log_debug_tx(tx, "request_header_finished_event: No user agent");
        return IB_OK;
    }
    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;
}
Beispiel #5
0
/**
 * 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;
        }
    }
Beispiel #6
0
/**
 * 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)
    );
}