int htp_connp_res_data(htp_connp_t *connp, const htp_time_t *timestamp, const void *data, size_t len) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data(connp->out_status %x)\n", connp->out_status); fprint_raw_data(stderr, __FUNCTION__, data, len); #endif // Return if the connection is in stop state if (connp->out_status == HTP_STREAM_STOP) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_INFO, 0, "Outbound parser is in HTP_STREAM_STOP"); return HTP_STREAM_STOP; } // Return if the connection has had a fatal error if (connp->out_status == HTP_STREAM_ERROR) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Outbound parser is in HTP_STREAM_ERROR"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA (previous error)\n"); #endif return HTP_STREAM_ERROR; } // If the length of the supplied data chunk is zero, proceed // only if the stream has been closed. We do not allow zero-sized // chunks in the API, but we use it internally to force the parsers // to finalize parsing. if ((len == 0) && (connp->out_status != HTP_STREAM_CLOSED)) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA (zero-length chunk)\n"); #endif return HTP_STREAM_CLOSED; } // Remember the timestamp of the current response data chunk if (timestamp != NULL) { memcpy(&connp->out_timestamp, timestamp, sizeof (*timestamp)); } // Store the current chunk information connp->out_current_data = (unsigned char *) data; connp->out_current_len = len; connp->out_current_read_offset = 0; connp->out_current_consume_offset = 0; connp->out_current_receiver_offset = 0; htp_conn_track_outbound_data(connp->conn, len, timestamp); // Return without processing any data if the stream is in tunneling // mode (which it would be after an initial CONNECT transaction. if (connp->out_status == HTP_STREAM_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_TUNNEL\n"); #endif return HTP_STREAM_TUNNEL; } // Invoke a processor, in a loop, until an error // occurs or until we run out of data. Many processors // will process a request, each pointing to the next // processor that needs to run. for (;;) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: out state=%s, progress=%s\n", htp_connp_out_state_as_string(connp), htp_tx_progress_as_string(connp->out_tx)); #endif // Return if there's been an error // or if we've run out of data. We are relying // on processors to add error messages, so we'll // keep quiet here. int rc = connp->out_state(connp); if (rc == HTP_OK) { if (connp->out_status == HTP_STREAM_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_TUNNEL\n"); #endif return HTP_STREAM_TUNNEL; } rc = htp_res_handle_state_change(connp); } if (rc != HTP_OK) { // Do we need more data? if ((rc == HTP_DATA) || (rc == HTP_DATA_BUFFER)) { htp_connp_res_receiver_send_data(connp, 0 /* not last */); if (rc == HTP_DATA_BUFFER) { htp_connp_res_buffer(connp); } #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA\n"); #endif connp->out_status = HTP_STREAM_DATA; return HTP_STREAM_DATA; } // Check for stop if (rc == HTP_STOP) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_STOP\n"); #endif connp->out_status = HTP_STREAM_STOP; return HTP_STREAM_STOP; } // Check for suspended parsing if (rc == HTP_DATA_OTHER) { // We might have actually consumed the entire data chunk? if (connp->out_current_read_offset >= connp->out_current_len) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA (suspended parsing)\n"); #endif connp->out_status = HTP_STREAM_DATA; // Do not send STREAM_DATE_DATA_OTHER if we've // consumed the entire chunk return HTP_STREAM_DATA; } else { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_DATA_OTHER\n"); #endif connp->out_status = HTP_STREAM_DATA_OTHER; // Partial chunk consumption return HTP_STREAM_DATA_OTHER; } } #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_res_data: returning HTP_STREAM_ERROR\n"); #endif // Remember that we've had an error. Errors are // not possible to recover from. connp->out_status = HTP_STREAM_ERROR; return HTP_STREAM_ERROR; } } return HTP_STREAM_ERROR; }
/** * Process a chunk of inbound (client or request) data. * * @param connp * @param timestamp Optional. * @param data * @param len * @return STREAM_STATE_DATA, STREAM_STATE_ERROR or STEAM_STATE_DATA_OTHER (see QUICK_START). STREAM_STATE_CLOSED and STREAM_STATE_TUNNEL are also possible. */ int htp_connp_req_data(htp_connp_t *connp, htp_time_t *timestamp, unsigned char *data, size_t len) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data(connp->in_status %x)\n", connp->in_status); fprint_raw_data(stderr, __FUNCTION__, data, len); #endif // Return if the connection is in stop state. if (connp->in_status == STREAM_STATE_STOP) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_INFO, 0, "Inbound parser is in STREAM_STATE_STOP"); return STREAM_STATE_STOP; } // Return if the connection had a fatal error earlier if (connp->in_status == STREAM_STATE_ERROR) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Inbound parser is in STREAM_STATE_ERROR"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (previous error)\n"); #endif return STREAM_STATE_ERROR; } // If the length of the supplied data chunk is zero, proceed // only if the stream has been closed. We do not allow zero-sized // chunks in the API, but we use them internally to force the parsers // to finalize parsing. if ((len == 0) && (connp->in_status != STREAM_STATE_CLOSED)) { htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed"); #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (zero-length chunk)\n"); #endif return STREAM_STATE_CLOSED; } // Remember the timestamp of the current request data chunk if (timestamp != NULL) { memcpy(&connp->in_timestamp, timestamp, sizeof(*timestamp)); } // Store the current chunk information connp->in_current_data = data; connp->in_current_len = len; connp->in_current_offset = 0; connp->in_chunk_count++; connp->conn->in_data_counter += len; connp->conn->in_packet_counter++; // Return without processing any data if the stream is in tunneling // mode (which it would be after an initial CONNECT transaction). if (connp->in_status == STREAM_STATE_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_TUNNEL\n"); #endif return STREAM_STATE_TUNNEL; } if (connp->out_status == STREAM_STATE_DATA_OTHER) { connp->out_status = STREAM_STATE_DATA; } // Invoke a processor, in a loop, until an error // occurs or until we run out of data. Many processors // will process a request, each pointing to the next // processor that needs to run. for (;;) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: in state=%s, progress=%s\n", htp_connp_in_state_as_string(connp), htp_tx_progress_as_string(connp->in_tx)); #endif // Return if there's been an error // or if we've run out of data. We are relying // on processors to add error messages, so we'll // keep quiet here. int rc = connp->in_state(connp); if (rc == HTP_OK) { if (connp->in_status == STREAM_STATE_TUNNEL) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_TUNNEL\n"); #endif return STREAM_STATE_TUNNEL; } } else { // Do we need more data? if (rc == HTP_DATA) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA\n"); #endif connp->in_status = STREAM_STATE_DATA; return STREAM_STATE_DATA; } // Check for suspended parsing if (rc == HTP_DATA_OTHER) { // We might have actually consumed the entire data chunk? if (connp->in_current_offset >= connp->in_current_len) { // Do not send STREAM_DATE_DATA_OTHER if we've // consumed the entire chunk #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (suspended parsing)\n"); #endif connp->in_status = STREAM_STATE_DATA; return STREAM_STATE_DATA; } else { // Partial chunk consumption #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA_OTHER\n"); #endif connp->in_status = STREAM_STATE_DATA_OTHER; return STREAM_STATE_DATA_OTHER; } } // Check for stop if (rc == HTP_STOP) { #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_STOP\n"); #endif connp->in_status = STREAM_STATE_STOP; return STREAM_STATE_STOP; } // If we're here that means we've encountered an error. connp->in_status = STREAM_STATE_ERROR; #ifdef HTP_DEBUG fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_ERROR (state response)\n"); #endif return STREAM_STATE_ERROR; } } }