/** * Determines whether inbound parsing needs to continue or stop. In * case the data appears to be plain text HTTP, we try to continue. * * @param[in] connp * @return HTP_OK if the parser can resume parsing, HTP_DATA_BUFFER if * we need more data. */ htp_status_t htp_connp_REQ_CONNECT_PROBE_DATA(htp_connp_t *connp) { for (;;) {//;i < max_read; i++) { IN_PEEK_NEXT(connp); // Have we reached the end of the line? For some reason // we can't test after IN_COPY_BYTE_OR_RETURN */ if (connp->in_next_byte == LF || connp->in_next_byte == 0x00) break; IN_COPY_BYTE_OR_RETURN(connp); } unsigned char *data; size_t len; if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) { fprintf(stderr, "htp_connp_req_consolidate_data fail"); return HTP_ERROR; } #ifdef HTP_DEBUG fprint_raw_data(stderr, "PROBING", data, len); #endif size_t pos = 0; size_t mstart = 0; // skip past leading whitespace. IIS allows this while ((pos < len) && htp_is_space(data[pos])) pos++; if (pos) mstart = pos; // The request method starts at the beginning of the // line and ends with the first whitespace character. while ((pos < len) && (!htp_is_space(data[pos]))) pos++; int methodi = HTP_M_UNKNOWN; bstr *method = bstr_dup_mem(data + mstart, pos - mstart); if (method) { methodi = htp_convert_method_to_number(method); bstr_free(method); } if (methodi != HTP_M_UNKNOWN) { #ifdef HTP_DEBUG fprint_raw_data(stderr, "htp_connp_REQ_CONNECT_PROBE_DATA: tunnel contains plain text HTTP", data, len); #endif connp->in_state = htp_connp_REQ_IDLE; } else { #ifdef HTP_DEBUG fprint_raw_data(stderr, "htp_connp_REQ_CONNECT_PROBE_DATA: tunnel is not HTTP", data, len); #endif connp->in_status = HTP_STREAM_TUNNEL; connp->out_status = HTP_STREAM_TUNNEL; } // not calling htp_connp_req_clear_buffer, we're not consuming the data return HTP_OK; }
/** * Parses request headers. * * @param[in] connp * @returns HTP_OK on state change, HTP_ERROR on error, or HTP_DATA when more data is needed. */ htp_status_t htp_connp_REQ_HEADERS(htp_connp_t *connp) { for (;;) { IN_COPY_BYTE_OR_RETURN(connp); // Have we reached the end of the line? if (connp->in_next_byte == LF) { unsigned char *data; size_t len; htp_connp_req_consolidate_data(connp, &data, &len); #ifdef HTP_DEBUG fprint_raw_data(stderr, __FUNCTION__, data, len); #endif // Should we terminate headers? if (htp_connp_is_line_terminator(connp, data, len)) { // Parse previous header, if any. if (connp->in_header != NULL) { if (connp->cfg->process_request_header(connp, bstr_ptr(connp->in_header), bstr_len(connp->in_header)) != HTP_OK) return HTP_ERROR; bstr_free(connp->in_header); connp->in_header = NULL; } htp_connp_req_clear_buffer(connp); // We've seen all the request headers. return htp_tx_state_request_headers(connp->in_tx); } htp_chomp(data, &len); // Check for header folding. if (htp_connp_is_line_folded(data, len) == 0) { // New header line. // Parse previous header, if any. if (connp->in_header != NULL) { if (connp->cfg->process_request_header(connp, bstr_ptr(connp->in_header), bstr_len(connp->in_header)) != HTP_OK) return HTP_ERROR; bstr_free(connp->in_header); connp->in_header = NULL; } IN_PEEK_NEXT(connp); if (htp_is_folding_char(connp->in_next_byte) == 0) { // Because we know this header is not folded, we can process the buffer straight away. if (connp->cfg->process_request_header(connp, data, len) != HTP_OK) return HTP_ERROR; } else { // Keep the partial header data for parsing later. connp->in_header = bstr_dup_mem(data, len); if (connp->in_header == NULL) return HTP_ERROR; } } else { // Folding; check that there's a previous header line to add to. if (connp->in_header == NULL) { // Invalid folding. // Warn only once per transaction. if (!(connp->in_tx->flags & HTP_INVALID_FOLDING)) { connp->in_tx->flags |= HTP_INVALID_FOLDING; htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid request field folding"); } // Keep the header data for parsing later. connp->in_header = bstr_dup_mem(data, len); if (connp->in_header == NULL) return HTP_ERROR; } else { // Add to the existing header. bstr *new_in_header = bstr_add_mem(connp->in_header, data, len); if (new_in_header == NULL) return HTP_ERROR; connp->in_header = new_in_header; } } htp_connp_req_clear_buffer(connp); } } return HTP_ERROR; }