New upstream version 0.5.32
Sascha Steinbiss
4 years ago
0 | 0.5.32 (13 December 2019) | |
1 | -------------------------- | |
2 | ||
3 | - bug fixes around pipelining | |
4 | ||
0 | 5 | 0.5.31 (24 September 2019) |
1 | 6 | -------------------------- |
2 | 7 |
43 | 43 | connp->last_error = NULL; |
44 | 44 | } |
45 | 45 | |
46 | void htp_connp_req_close(htp_connp_t *connp, const htp_time_t *timestamp) { | |
47 | if (connp == NULL) return; | |
48 | ||
49 | // Update internal flags | |
50 | if (connp->in_status != HTP_STREAM_ERROR) | |
51 | connp->in_status = HTP_STREAM_CLOSED; | |
52 | ||
53 | // Call the parsers one last time, which will allow them | |
54 | // to process the events that depend on stream closure | |
55 | htp_connp_req_data(connp, timestamp, NULL, 0); | |
56 | } | |
57 | ||
46 | 58 | void htp_connp_close(htp_connp_t *connp, const htp_time_t *timestamp) { |
47 | 59 | if (connp == NULL) return; |
48 | 60 |
56 | 56 | * @param[in] timestamp Optional. |
57 | 57 | */ |
58 | 58 | void htp_connp_close(htp_connp_t *connp, const htp_time_t *timestamp); |
59 | void htp_connp_req_close(htp_connp_t *connp, const htp_time_t *timestamp); | |
59 | 60 | |
60 | 61 | /** |
61 | 62 | * Creates a new connection parser using the provided configuration. Because |
827 | 827 | } |
828 | 828 | |
829 | 829 | htp_status_t htp_connp_REQ_FINALIZE(htp_connp_t *connp) { |
830 | size_t bytes_left = connp->in_current_len - connp->in_current_read_offset; | |
831 | ||
832 | if (bytes_left > 0) { | |
833 | // If we have more bytes | |
834 | // Either it is request pipelining | |
835 | // Or we interpret it as body data | |
836 | int64_t pos = connp->in_current_read_offset; | |
837 | int64_t mstart = 0; | |
838 | // skip past leading whitespace. IIS allows this | |
839 | while ((pos < connp->in_current_len) && htp_is_space(connp->in_current_data[pos])) | |
840 | pos++; | |
841 | if (pos < connp->in_current_len) { | |
842 | mstart = pos; | |
843 | // The request method starts at the beginning of the | |
844 | // line and ends with the first whitespace character. | |
845 | while ((pos < connp->in_current_len) && (!htp_is_space(connp->in_current_data[pos]))) | |
846 | pos++; | |
847 | ||
848 | int methodi = HTP_M_UNKNOWN; | |
849 | bstr *method = bstr_dup_mem(connp->in_current_data + mstart, pos - mstart); | |
850 | if (method) { | |
851 | methodi = htp_convert_method_to_number(method); | |
852 | bstr_free(method); | |
853 | } | |
854 | if (methodi == HTP_M_UNKNOWN) { | |
855 | // Interpret remaining bytes as body data | |
856 | htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected request body"); | |
857 | connp->in_tx->request_progress = HTP_REQUEST_BODY; | |
858 | connp->in_state = htp_connp_REQ_BODY_IDENTITY; | |
859 | connp->in_body_data_left = bytes_left; | |
860 | return HTP_OK; | |
861 | } | |
862 | } | |
863 | } | |
830 | if (connp->in_status != HTP_STREAM_CLOSED) { | |
831 | IN_PEEK_NEXT(connp); | |
832 | if (connp->in_next_byte == -1) { | |
833 | return htp_tx_state_request_complete(connp->in_tx); | |
834 | } | |
835 | if (connp->in_next_byte != LF || connp->in_current_consume_offset >= connp->in_current_read_offset) { | |
836 | for (;;) {//;i < max_read; i++) { | |
837 | IN_COPY_BYTE_OR_RETURN(connp); | |
838 | // Have we reached the end of the line? For some reason | |
839 | // we can't test after IN_COPY_BYTE_OR_RETURN */ | |
840 | if (connp->in_next_byte == LF) | |
841 | break; | |
842 | } | |
843 | } | |
844 | } | |
845 | ||
846 | unsigned char *data; | |
847 | size_t len; | |
848 | if (htp_connp_req_consolidate_data(connp, &data, &len) != HTP_OK) { | |
849 | return HTP_ERROR; | |
850 | } | |
851 | #ifdef HTP_DEBUG | |
852 | fprint_raw_data(stderr, "PROBING request finalize", data, len); | |
853 | #endif | |
854 | if (len == 0) { | |
855 | //closing | |
856 | return htp_tx_state_request_complete(connp->in_tx); | |
857 | } | |
858 | ||
859 | size_t pos = 0; | |
860 | size_t mstart = 0; | |
861 | // skip past leading whitespace. IIS allows this | |
862 | while ((pos < len) && htp_is_space(data[pos])) | |
863 | pos++; | |
864 | if (pos) | |
865 | mstart = pos; | |
866 | // The request method starts at the beginning of the | |
867 | // line and ends with the first whitespace character. | |
868 | while ((pos < len) && (!htp_is_space(data[pos]))) | |
869 | pos++; | |
870 | ||
871 | if (pos > mstart) { | |
872 | int methodi = HTP_M_UNKNOWN; | |
873 | bstr *method = bstr_dup_mem(data + mstart, pos - mstart); | |
874 | if (method) { | |
875 | methodi = htp_convert_method_to_number(method); | |
876 | bstr_free(method); | |
877 | } | |
878 | if (methodi == HTP_M_UNKNOWN) { | |
879 | // Interpret remaining bytes as body data | |
880 | htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected request body"); | |
881 | htp_status_t rc = htp_tx_req_process_body_data_ex(connp->in_tx, data, len); | |
882 | htp_connp_req_clear_buffer(connp); | |
883 | return rc; | |
884 | } | |
885 | } | |
886 | //else | |
887 | //unread last end of line so that REQ_LINE works | |
888 | if (connp->in_current_read_offset < (int64_t)len) { | |
889 | connp->in_current_read_offset=0; | |
890 | } else { | |
891 | connp->in_current_read_offset-=len; | |
892 | } | |
893 | if (connp->in_current_read_offset < connp->in_current_consume_offset) { | |
894 | connp->in_current_consume_offset=connp->in_current_read_offset; | |
895 | } | |
896 | ||
864 | 897 | return htp_tx_state_request_complete(connp->in_tx); |
865 | 898 | } |
866 | 899 |
1069 | 1069 | } |
1070 | 1070 | |
1071 | 1071 | htp_status_t htp_connp_RES_FINALIZE(htp_connp_t *connp) { |
1072 | int bytes_left = connp->out_current_len - connp->out_current_read_offset; | |
1073 | unsigned char * data = connp->out_current_data + connp->out_current_read_offset; | |
1074 | ||
1075 | if (bytes_left > 0 && | |
1076 | htp_treat_response_line_as_body(data, bytes_left)) { | |
1072 | if (connp->out_status != HTP_STREAM_CLOSED) { | |
1073 | OUT_PEEK_NEXT(connp); | |
1074 | if (connp->out_next_byte == -1) { | |
1075 | return htp_tx_state_response_complete_ex(connp->out_tx, 0); | |
1076 | } | |
1077 | if (connp->out_next_byte != LF || connp->out_current_consume_offset >= connp->out_current_read_offset) { | |
1078 | for (;;) {//;i < max_read; i++) { | |
1079 | OUT_COPY_BYTE_OR_RETURN(connp); | |
1080 | // Have we reached the end of the line? For some reason | |
1081 | // we can't test after IN_COPY_BYTE_OR_RETURN */ | |
1082 | if (connp->out_next_byte == LF) | |
1083 | break; | |
1084 | } | |
1085 | } | |
1086 | } | |
1087 | size_t bytes_left; | |
1088 | unsigned char * data; | |
1089 | ||
1090 | if (htp_connp_res_consolidate_data(connp, &data, &bytes_left) != HTP_OK) { | |
1091 | return HTP_ERROR; | |
1092 | } | |
1093 | #ifdef HTP_DEBUG | |
1094 | fprint_raw_data(stderr, "PROBING response finalize", data, bytes_left); | |
1095 | #endif | |
1096 | if (bytes_left == 0) { | |
1097 | //closing | |
1098 | return htp_tx_state_response_complete_ex(connp->out_tx, 0); | |
1099 | } | |
1100 | ||
1101 | if (htp_treat_response_line_as_body(data, bytes_left)) { | |
1077 | 1102 | // Interpret remaining bytes as body data |
1078 | 1103 | htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Unexpected response body"); |
1079 | connp->out_current_read_offset += bytes_left; | |
1080 | connp->out_current_consume_offset += bytes_left; | |
1081 | connp->out_stream_offset += bytes_left; | |
1082 | connp->out_body_data_left -= bytes_left; | |
1083 | 1104 | htp_status_t rc = htp_tx_res_process_body_data_ex(connp->out_tx, data, bytes_left); |
1105 | htp_connp_res_clear_buffer(connp); | |
1084 | 1106 | return rc; |
1085 | 1107 | } |
1086 | 1108 | |
1109 | //unread last end of line so that RES_LINE works | |
1110 | if (connp->out_current_read_offset < (int64_t)bytes_left) { | |
1111 | connp->out_current_read_offset=0; | |
1112 | } else { | |
1113 | connp->out_current_read_offset-=bytes_left; | |
1114 | } | |
1115 | if (connp->out_current_read_offset < connp->out_current_consume_offset) { | |
1116 | connp->out_current_consume_offset=connp->out_current_read_offset; | |
1117 | } | |
1087 | 1118 | return htp_tx_state_response_complete_ex(connp->out_tx, 0 /* not hybrid mode */); |
1088 | 1119 | } |
1089 | 1120 | |
1111 | 1142 | connp->out_tx = htp_list_get(connp->conn->transactions, connp->out_next_tx_index); |
1112 | 1143 | if (connp->out_tx == NULL) { |
1113 | 1144 | htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Unable to match response to request"); |
1145 | // finalize dangling request waiting for next request or body | |
1146 | if (connp->in_state == htp_connp_REQ_FINALIZE) { | |
1147 | htp_tx_state_request_complete(connp->in_tx); | |
1148 | } | |
1114 | 1149 | connp->out_tx = htp_connp_tx_create(connp); |
1115 | 1150 | if (connp->out_tx == NULL) { |
1116 | 1151 | return HTP_ERROR; |
3 | 3 | Content-Type: application/x-www-form-urlencoded |
4 | 4 | |
5 | 5 | login=foo&password=bar |
6 | ||
6 | 7 | <<< |
7 | 8 | HTTP/1.1 200 OK |
8 | 9 | Content-Length: 0 |
0 | >>> | |
1 | GET /?p=%20 HTTP/1.1 | |
2 | User-Agent: Mozilla | |
3 | ||
4 | G | |
5 | >>> | |
6 | ET /?p=%21 HTTP/1.1 | |
7 | User-Agent: Mozilla | |
8 |
0 | >>> | |
1 | GET /?p=%20 HTTP/1.1 | |
2 | User-Agent: Mozilla | |
3 | ||
4 | GET /?p=%21 HTTP/1.1 | |
5 | User-Agent: Mozilla | |
6 | ||
7 | <<< | |
8 | HTTP/1.0 200 OK | |
9 | Date: Mon, 31 Aug 2009 20:25:50 GMT | |
10 | Server: Apache | |
11 | Connection: close | |
12 | Content-Type: text/html | |
13 | Content-Length: 14 | |
14 | ||
15 | Hello World! | |
16 | H | |
17 | <<< | |
18 | TTP/1.0 200 OK | |
19 | Date: Mon, 31 Aug 2009 20:25:50 GMT | |
20 | Server: Apache | |
21 | Connection: close | |
22 | Content-Type: text/html | |
23 | Content-Length: 13 | |
24 | ||
25 | Hello People!⏎ |
1482 | 1482 | htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); |
1483 | 1483 | ASSERT_TRUE(tx != NULL); |
1484 | 1484 | |
1485 | ASSERT_EQ(1, tx->request_ignored_lines); | |
1485 | /*part of previous request body ASSERT_EQ(1, tx->request_ignored_lines);*/ | |
1486 | 1486 | } |
1487 | 1487 | |
1488 | 1488 | TEST_F(ConnectionParsing, PostNoBody) { |
1593 | 1593 | htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); |
1594 | 1594 | ASSERT_TRUE(tx != NULL); |
1595 | 1595 | |
1596 | ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); | |
1596 | //error first ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); | |
1597 | 1597 | ASSERT_EQ(HTP_RESPONSE_HEADERS, tx->response_progress); |
1598 | 1598 | } |
1599 | 1599 | |
2031 | 2031 | ASSERT_EQ(68, tx->response_entity_len); |
2032 | 2032 | } |
2033 | 2033 | #endif |
2034 | ||
2035 | TEST_F(ConnectionParsing, RequestsCut) { | |
2036 | int rc = test_run(home, "97-requests-cut.t", cfg, &connp); | |
2037 | ASSERT_GE(rc, 0); | |
2038 | ||
2039 | ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); | |
2040 | htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); | |
2041 | ASSERT_TRUE(tx != NULL); | |
2042 | ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); | |
2043 | ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); | |
2044 | ||
2045 | tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); | |
2046 | ASSERT_TRUE(tx != NULL); | |
2047 | ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); | |
2048 | ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); | |
2049 | } | |
2050 | ||
2051 | TEST_F(ConnectionParsing, ResponsesCut) { | |
2052 | int rc = test_run(home, "98-responses-cut.t", cfg, &connp); | |
2053 | ASSERT_GE(rc, 0); | |
2054 | ||
2055 | ASSERT_EQ(2, htp_list_size(connp->conn->transactions)); | |
2056 | htp_tx_t *tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 0); | |
2057 | ASSERT_TRUE(tx != NULL); | |
2058 | ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); | |
2059 | ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); | |
2060 | ASSERT_EQ(200, tx->response_status_number); | |
2061 | ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); | |
2062 | ||
2063 | tx = (htp_tx_t *) htp_list_get(connp->conn->transactions, 1); | |
2064 | ASSERT_TRUE(tx != NULL); | |
2065 | ASSERT_EQ(0, bstr_cmp_c(tx->request_method, "GET")); | |
2066 | ASSERT_EQ(HTP_REQUEST_COMPLETE, tx->request_progress); | |
2067 | ASSERT_EQ(200, tx->response_status_number); | |
2068 | ASSERT_EQ(HTP_RESPONSE_COMPLETE, tx->response_progress); | |
2069 | } |