Exemple #1
0
/**
 * Processes identity request body.
 *
 * @param connp
 * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed.
 */
int htp_connp_REQ_BODY_IDENTITY(htp_connp_t *connp) {
    htp_tx_data_t d;

    d.tx = connp->in_tx;
    d.data = &connp->in_current_data[connp->in_current_offset];
    d.len = 0;

    for (;;) {
        IN_NEXT_BYTE(connp);

        if (connp->in_next_byte == -1) {
            // End of chunk

            int rc = htp_req_run_hook_body_data(connp, &d);
            if (rc != HOOK_OK) {
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                    "Request body data callback returned error (%d)", rc);
                return HTP_ERROR;
            }

            // Ask for more data
            return HTP_DATA;
        } else {
            connp->in_tx->request_message_len++;
            connp->in_tx->request_entity_len++;
            connp->in_body_data_left--;
            d.len++;

            if (connp->in_body_data_left == 0) {
                // End of body

                int rc = htp_req_run_hook_body_data(connp, &d);
                if (rc != HOOK_OK) {
                    htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                        "Request body data callback returned error (%d)", rc);
                    return HTP_ERROR;
                }

                // Done
                connp->in_state = htp_connp_REQ_IDLE;
                connp->in_tx->progress = TX_PROGRESS_WAIT;

                return HTP_OK;
            }
        }
    }
}
Exemple #2
0
/**
 * Processes a chunk of data.
 *
 * @param connp
 * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed.
 */
int htp_connp_REQ_BODY_CHUNKED_DATA(htp_connp_t *connp) {
    htp_tx_data_t d;

    d.tx = connp->in_tx;
    d.data = &connp->in_current_data[connp->in_current_offset];
    d.len = 0;

    for (;;) {
        IN_NEXT_BYTE(connp);

        if (connp->in_next_byte == -1) {
            // Send data to callbacks            
            int rc = htp_req_run_hook_body_data(connp, &d);
            if (rc != HOOK_OK) {
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                    "Request body data callback returned error (%d)", rc);
                return HTP_ERROR;
            }

            // Ask for more data
            return HTP_DATA;
        } else {
            connp->in_tx->request_message_len++;
            connp->in_tx->request_entity_len++;
            connp->in_chunked_length--;
            d.len++;

            if (connp->in_chunked_length == 0) {
                // End of data chunk

                // Send data to callbacks               
                int rc = htp_req_run_hook_body_data(connp, &d);
                if (rc != HOOK_OK) {
                    htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                        "Request body data callback returned error (%d)", rc);
                    return HTP_ERROR;
                }

                connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA_END;

                return HTP_OK;
            }
        }
    }
}
htp_status_t htp_tx_req_process_body_data(htp_tx_t *tx, const void *data, size_t len) {
    // Keep track of the body length.
    tx->request_entity_len += len;

    // Send data to the callbacks.

    htp_tx_data_t d;
    d.tx = tx;
    d.data = (unsigned char *) data;
    d.len = len;

    int rc = htp_req_run_hook_body_data(tx->connp, &d);
    if (rc != HTP_OK) {
        htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                "Request body data callback returned error (%d)", rc);
        return HTP_ERROR;
    }

    return HTP_OK;
}
htp_status_t htp_tx_req_process_body_data_ex(htp_tx_t *tx, const void *data, size_t len) {
    if (tx == NULL) return HTP_ERROR;

    // NULL data is allowed in this private function; it's
    // used to indicate the end of request body.

    // Keep track of the body length.
    tx->request_entity_len += len;

    // Send data to the callbacks.

    htp_tx_data_t d;
    d.tx = tx;
    d.data = (unsigned char *) data;
    d.len = len;

    htp_status_t rc = htp_req_run_hook_body_data(tx->connp, &d);
    if (rc != HTP_OK) {
        htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request body data callback returned error (%d)", rc);
        return HTP_ERROR;
    }

    return HTP_OK;
}
Exemple #5
0
/**
 * The idle state is invoked before and after every transaction. Consequently,
 * it will start a new transaction when data is available and finalise a transaction
 * which has been processed.
 *
 * @param connp
 * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed.
 */
int htp_connp_REQ_IDLE(htp_connp_t * connp) {
    // If we're here and a transaction object exists that
    // means we've just completed parsing a request. We need
    // to run the final hook and start over.
    if (connp->in_tx != NULL) {
        // Run the last REQUEST_BODY_DATA HOOK, but
        // only if there was a request body
        if (connp->in_tx->request_transfer_coding != -1) {
            htp_tx_data_t d;
            d.data = NULL;
            d.len = 0;
            d.tx = connp->in_tx;
            htp_req_run_hook_body_data(connp, &d);
        }

        // Run hook REQUEST
        int rc = hook_run_all(connp->cfg->hook_request, connp);
        if (rc != HOOK_OK) {
            switch (rc) {
                case HOOK_STOP:
                    return HTP_STOP;
                case HOOK_ERROR:
                case HOOK_DECLINED:
                default:
                    htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                        "Request headers callback returned error (%d)", rc);
                    return HTP_ERROR;
            }
        }

        // Clean-up
        if (connp->put_file != NULL) {
            bstr_free(&connp->put_file->filename);
            free(connp->put_file);
            connp->put_file = NULL;
        }

        // Start afresh
        connp->in_tx = NULL;
    }

    // We want to start parsing the next request (and change
    // the state from IDLE) only if there's at least one
    // byte of data available. Otherwise we could be creating
    // new structures even if there's no more data on the
    // connection.
    IN_TEST_NEXT_BYTE_OR_RETURN(connp);

    // Detect pipelining
    if (list_size(connp->conn->transactions) > connp->out_next_tx_index) {
        connp->conn->flags |= PIPELINED_CONNECTION;
    }

    // Parsing a new request
    connp->in_tx = htp_tx_create(connp->cfg, CFG_SHARED, connp->conn);
    if (connp->in_tx == NULL) return HTP_ERROR;

    connp->in_tx->connp = connp;

    list_add(connp->conn->transactions, connp->in_tx);

    connp->in_content_length = -1;
    connp->in_body_data_left = -1;
    connp->in_header_line_index = -1;
    connp->in_header_line_counter = 0;
    connp->in_chunk_request_index = connp->in_chunk_count;

    // Run hook TRANSACTION_START
    int rc = hook_run_all(connp->cfg->hook_transaction_start, connp);
    if (rc != HOOK_OK) {
        switch (rc) {
            case HOOK_STOP:
                return HTP_STOP;
            case HOOK_ERROR:
            case HOOK_DECLINED:
            default:
                htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0,
                    "Request headers callback returned error (%d)", rc);
                return HTP_ERROR;
        }
    }

    // Change state into request line parsing
    connp->in_state = htp_connp_REQ_LINE;
    connp->in_tx->progress = TX_PROGRESS_REQ_LINE;

    return HTP_OK;
}