Exemplo n.º 1
0
/**
 * IronBee callback function to set an HTTP error status.
 * This will divert processing into an ErrorDocument for the status.
 *
 * @param[in] tx - IronBee transaction
 * @param[in] status - Status to set
 * @return OK, or Declined if called too late.  NOTIMPL should never happen.
 */
static ib_status_t ib_error_callback(ib_tx_t *tx, int status, void *cbdata)
{
    ngxib_req_ctx *ctx = tx->sctx;
    if (status >= 200 && status < 600) {
        if (ctx->status >= 200 && ctx->status < 600) {
            ib_log_notice_tx(tx, "Ignoring: status already set to %d", ctx->status);
            return IB_OK;
        }
        if (ctx->start_response) {
            ib_log_notice_tx(tx, "Too late to change status=%d", status);
            return IB_DECLINED;
        }
        ib_log_info_tx(tx, "Setting status: %d -> %d", ctx->status, status);
        ctx->status = status;
        return IB_OK;
    }
    return IB_ENOTIMPL;
}
Exemplo n.º 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;
}
Exemplo n.º 3
0
ib_status_t ib_parsed_req_line_create(ib_tx_t *tx,
                                      ib_parsed_req_line_t **line,
                                      const char *raw,
                                      size_t raw_len,
                                      const char *method,
                                      size_t method_len,
                                      const char *uri,
                                      size_t uri_len,
                                      const char *protocol,
                                      size_t protocol_len)
{
    ib_status_t rc = IB_OK;

    assert(tx != NULL);
    assert(tx->ib != NULL);
    assert(tx->mp != NULL);

    ib_parsed_req_line_t *line_tmp = ib_mpool_alloc(tx->mp,
                                                    sizeof(*line_tmp));

    if ( line_tmp == NULL ) {
        *line = NULL;
        return IB_EALLOC;
    }

    /* Record the components if available. If the components are
     * not available, but the raw line is, then it will be possible
     * to parse the components out later on.  Otherwise, if there
     * is no component and no raw line, then set default values.
     */
    if (method != NULL) {
        rc = ib_bytestr_dup_mem(&line_tmp->method,
                                tx->mp,
                                (const uint8_t *)method,
                                method_len);
        if (rc != IB_OK) {
            return rc;
        }
    }
    else {
        rc = ib_bytestr_dup_mem(&line_tmp->method,
                                tx->mp,
                                (const uint8_t *)"",
                                0);
        if (rc != IB_OK) {
            return rc;
        }
    }

    if (uri != NULL) {
        rc = ib_bytestr_dup_mem(&line_tmp->uri,
                                tx->mp,
                                (const uint8_t *)uri,
                                uri_len);
        if (rc != IB_OK) {
            return rc;
        }
    }
    else {
        rc = ib_bytestr_dup_mem(&line_tmp->uri,
                                tx->mp,
                                (const uint8_t *)"",
                                0);
        if (rc != IB_OK) {
            return rc;
        }
    }

    if (protocol != NULL) {
        rc = ib_bytestr_dup_mem(&line_tmp->protocol,
                                tx->mp,
                                (const uint8_t *)protocol,
                                protocol_len);
        if (rc != IB_OK) {
            return rc;
        }
    }
    else {
        rc = ib_bytestr_dup_mem(&line_tmp->protocol,
                                tx->mp,
                                (const uint8_t *)"",
                                0);
        if (rc != IB_OK) {
            return rc;
        }
    }

    /* If no raw line is available, then create one. */
    if (raw == NULL) {
        if (method_len + uri_len + protocol_len == 0) {
            ib_log_notice_tx(tx,
                "Unable to generate raw request line without line "
                "components - using zero length request line."
            );

            rc = ib_bytestr_dup_mem(&line_tmp->raw,
                                    tx->mp,
                                    (const uint8_t *)"",
                                    0);
            if (rc != IB_OK) {
                return rc;
            }
        }
        else {
            size_t raw_line_len;

            assert(method != NULL);
            assert(uri != NULL);

            /* Create a correctly sized bytestr and manually copy
             * the data into it.
             */
            raw_line_len = method_len + 1 + uri_len +
                           (protocol == NULL ? 0 : 1 + protocol_len);
            rc = ib_bytestr_create(&line_tmp->raw, tx->mp, raw_line_len);
            if (rc != IB_OK) {
                return rc;
            }

            ib_log_debug_tx(tx,
                            "Generating raw request line from components "
                            "(length %zd).", raw_line_len);

            ib_bytestr_append_mem(line_tmp->raw,
                                  (const uint8_t *)method,
                                  method_len);
            ib_bytestr_append_mem(line_tmp->raw,
                                  (const uint8_t *)" ",
                                  1);
            ib_bytestr_append_mem(line_tmp->raw,
                                  (const uint8_t *)uri,
                                  uri_len);
            if (protocol != NULL) {
                ib_bytestr_append_mem(line_tmp->raw,
                                      (const uint8_t *)" ",
                                      1);
                ib_bytestr_append_mem(line_tmp->raw,
                                      (const uint8_t *)protocol,
                                      protocol_len);
            }
        }
    }
    else {
        rc = ib_bytestr_dup_mem(&line_tmp->raw,
                                tx->mp,
                                (const uint8_t *)raw,
                                raw_len);
        if (rc != IB_OK) {
            return rc;
        }

        /* Now, if all components are missing, then parse them out
         * from the raw line.  If only some are missing, then
         * do not assume anything is parsable.
         *
         * NOTE: This is a strict HTTP parser and assumes single
         *       space (0x20) component separators. Better is to
         *       have the server parse the components properly.
         */
        if ((method == NULL) && (uri == NULL) && (protocol == NULL)) {
            uint8_t *raw_end = (uint8_t *)(raw + raw_len) - 1;
            uint8_t *ptr = (uint8_t *)raw;
            const uint8_t *parsed_field = ptr;

            ib_log_debug_tx(tx, "Parsing raw request line into components.");

            /* Parse the method. */
            while (ptr <= raw_end) {
                if (*ptr == ' ') {
                    break;
                }
                ++ptr;
            }
            rc = ib_bytestr_dup_mem(&line_tmp->method,
                                    tx->mp,
                                    parsed_field,
                                    (ptr - parsed_field));
            if (rc != IB_OK) {
                return rc;
            }

            /* Parse the uri. */
            parsed_field = ++ptr;
            while (ptr <= raw_end) {
                if (*ptr == ' ') {
                    break;
                }
                ++ptr;
            }
            rc = ib_bytestr_dup_mem(&line_tmp->uri,
                                    tx->mp,
                                    parsed_field,
                                    (ptr - parsed_field));
            if (rc != IB_OK) {
                return rc;
            }

            /* Parse the protocol. */
            parsed_field = ++ptr;
            if (parsed_field <= raw_end) {
                rc = ib_bytestr_dup_mem(&line_tmp->protocol,
                                        tx->mp,
                                        parsed_field,
                                        (raw_end - parsed_field) + 1);
                if (rc != IB_OK) {
                    return rc;
                }
            }
            else {
                rc = ib_bytestr_dup_mem(&line_tmp->protocol,
                                        tx->mp,
                                        (const uint8_t *)"",
                                        0);
                if (rc != IB_OK) {
                    return rc;
                }
            }
        }
    }

    /* Commit back successfully created line. */
    *line = line_tmp;

    return IB_OK;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
/*
 * 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", &param_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));
                }
            }
Exemplo n.º 6
0
/*
 * 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;
    ib_conn_t *conn = tx->conn;

    assert(ib != NULL);
    assert(tx != NULL);
    assert(event == handle_request_header_event);

    core_gen_tx_bytestr_alias2(tx, "server_addr",
                               conn->local_ipstr,
                               strlen(conn->local_ipstr));

    core_gen_tx_numeric(tx, "server_port", conn->local_port);

    core_gen_tx_bytestr_alias2(tx, "remote_addr",
                               conn->remote_ipstr,
                               strlen(conn->remote_ipstr));


    core_gen_tx_numeric(tx, "remote_port", conn->remote_port);

    core_gen_tx_numeric(tx, "conn_tx_count",
                        tx->conn->tx_count);

    if (tx->request_line != NULL) {
        core_gen_tx_bytestr_alias(tx, "request_line",
                                  tx->request_line->raw);

        core_gen_tx_bytestr_alias(tx, "request_method",
                                  tx->request_line->method);

        core_gen_tx_bytestr_alias(tx, "request_uri_raw",
                                  tx->request_line->uri);

        core_gen_tx_bytestr_alias(tx, "request_protocol",
                                  tx->request_line->protocol);
    }

    /* Populate the ARGS collection. */
    rc = core_slow_get(&f, tx, "ARGS");
    if (rc == IB_OK) {
        ib_field_t *param_list;

        rc = core_slow_get(&param_list, tx, "request_uri_params");
        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));
                }
            }