diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:40:56 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:40:56 +0000 |
commit | c248d29056abbc1fc4c5dc178bab48fb8d2c1fcb (patch) | |
tree | 4a13fc30604509224504e1911bc976e5df7bdf05 /test/test-tcpick.c | |
parent | Initial commit. (diff) | |
download | libhtp-c248d29056abbc1fc4c5dc178bab48fb8d2c1fcb.tar.xz libhtp-c248d29056abbc1fc4c5dc178bab48fb8d2c1fcb.zip |
Adding upstream version 1:0.5.47.upstream/1%0.5.47
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test/test-tcpick.c')
-rw-r--r-- | test/test-tcpick.c | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/test/test-tcpick.c b/test/test-tcpick.c new file mode 100644 index 0000000..b0bc14f --- /dev/null +++ b/test/test-tcpick.c @@ -0,0 +1,351 @@ +/*************************************************************************** + * Copyright (c) 2009-2010 Open Information Security Foundation + * Copyright (c) 2010-2013 Qualys, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + + * - Neither the name of the Qualys, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ***************************************************************************/ + +/** + * @file + * @author Ivan Ristic <ivanr@webkreator.com> + */ + +#include <ctype.h> +#include <dirent.h> +#include <sys/time.h> +#include <sys/types.h> +#include <time.h> + +#include "../htp/htp.h" + +#define CLIENT 1 +#define SERVER 2 + +static int parse_filename(const char *filename, char **remote_addr, char **local_addr) { + char *copy = strdup(filename); + char *p, *saveptr; + + char *start = copy; + char *q = strrchr(copy, '/'); + if (q != NULL) start = q; + + q = strrchr(start, '\\'); + if (q != NULL) start = q; + + int count = 0; + p = strtok_r(start, "_", &saveptr); + while (p != NULL) { + count++; + // printf("%i %s\n", count, p); + + switch (count) { + case 3: + *remote_addr = strdup(p); + break; + case 4: + *local_addr = strdup(p); + break; + } + + p = strtok_r(NULL, "_", &saveptr); + } + + free(copy); + + return 0; +} + +static int parse_chunk_info(char *buf, size_t *response_offset, size_t *response_len) { + char *p = buf; + size_t lastlen; + + while ((*p != ']') && (p != '\0')) p++; + if (*p == '\0') return -1; + p++; + + while (isspace(*p)) p++; + + *response_offset = bstr_util_mem_to_pint(p, strlen(p), 10, &lastlen); + + p += lastlen; + + while ((*p != '(') && (p != '\0')) p++; + if (*p == '\0') return -1; + p++; + + *response_len = bstr_util_mem_to_pint(p, strlen(p), 10, &lastlen); + + return 1; +} + +static int tcpick_run_file(const char *filename, htp_cfg_t *cfg, htp_connp_t **connp) { + struct timeval tv; + char buf[1025]; + int first = -1, current = -1; + char *remote_addr, *local_addr; + + char *request_last_chunk = NULL; + char *response_last_chunk = NULL; + size_t request_offset, request_len; + size_t request_last_offset = 0, request_last_len = 0; + size_t response_offset, response_len; + size_t response_last_offset = 0, response_last_len = 0; + + if (parse_filename(filename, &remote_addr, &local_addr) < 0) { + printf("Failed to parse filename: %s\n", filename); + return -1; + } + + FILE *f = fopen(filename, "rb"); + if (f == NULL) { + printf("Unable to open file: %s\n", filename); + return -1; + } + + gettimeofday(&tv, NULL); + + // Create parser + *connp = htp_connp_create(cfg); + + // Find all chunks and feed them to the parser + while (fgets(buf, 1024, f) != NULL) { + // Ignore empty lines + if (buf[0] == LF) { + continue; + } + + if (strncmp(buf, "[server", 7) == 0) { + current = SERVER; + } else { + current = CLIENT; + } + + if (first == -1) { + first = current; + + if (first == SERVER) { + htp_connp_open(*connp, local_addr, 80, remote_addr, 80, &tv); + } else { + htp_connp_open(*connp, remote_addr, 80, local_addr, 80, &tv); + } + } + + int len = 0; + + if (first == current) { + if (parse_chunk_info(buf, &request_offset, &request_len) < 0) { + printf("Invalid line: %s", buf); + fclose(f); + htp_connp_destroy_all(*connp); + *connp = NULL; + return -1; + } + + len = request_len; + + // printf("# Request offset %i len %i\n", request_offset, request_len); + } else { + if (parse_chunk_info(buf, &response_offset, &response_len) < 0) { + printf("Invalid line: %s", buf); + fclose(f); + htp_connp_destroy_all(*connp); + *connp = NULL; + return -1; + } + + len = response_len; + + // printf("# Response offset %i len %i\n", response_offset, response_len); + } + + // printf("Len: %i\n", len); + + if (len <= 0) { + printf("Invalid length: %i\n", len); + fclose(f); + htp_connp_destroy_all(*connp); + *connp = NULL; + return -1; + } + + char *data = malloc(len); + if (data == NULL) { + printf("Failed to allocate %i bytes\n", len); + fclose(f); + htp_connp_destroy_all(*connp); + *connp = NULL; + return -1; + } + + int read = fread(data, 1, len, f); + if (read != len) { + // printf("Failed to read %i bytes (got %i)\n", len, read); + fclose(f); + htp_connp_destroy_all(*connp); + *connp = NULL; + return -1; + } + + if (first == current) { + if ((request_last_chunk == NULL) || (request_len != request_last_len) || (memcmp(data, request_last_chunk, request_len) != 0)) { + // printf("# Parse request data: %i byte(s)\n", len); + if (htp_connp_req_data(*connp, &tv, data, len) == HTP_ERROR) { + fclose(f); + return -1; + } + } + + request_last_offset = request_offset; + request_last_len = request_len; + if (request_last_chunk != NULL) { + free(request_last_chunk); + } + request_last_chunk = data; + } else { + if ((response_last_chunk == NULL) || (response_len != response_last_len) || (memcmp(data, response_last_chunk, response_len) != 0)) { + // printf("# Parse response data: %i byte(s)\n", len); + if (htp_connp_res_data(*connp, &tv, data, len) == HTP_ERROR) { + fclose(f); + return -1; + } + } + + response_last_offset = response_offset; + response_last_len = response_len; + if (response_last_chunk != NULL) { + free(response_last_chunk); + } + response_last_chunk = data; + } + } + + fclose(f); + + htp_connp_close(*connp, &tv); + + return 1; +} + +static void print_tx(htp_connp_t *connp, htp_tx_t *tx) { + char *request_line = bstr_util_strdup_to_c(tx->request_line); + htp_header_t *h_user_agent = htp_table_get_c(tx->request_headers, "user-agent"); + htp_header_t *h_referer = htp_table_get_c(tx->request_headers, "referer"); + char *referer, *user_agent; + char buf[256]; + + time_t t = time(NULL); + struct tm *tmp = localtime(&t); + + strftime(buf, 255, "%d/%b/%Y:%T %z", tmp); + + if (h_user_agent == NULL) user_agent = strdup("-"); + else { + user_agent = bstr_util_strdup_to_c(h_user_agent->value); + } + + if (h_referer == NULL) referer = strdup("-"); + else { + referer = bstr_util_strdup_to_c(h_referer->value); + } + + printf("%s - - [%s] \"%s\" %i %zu \"%s\" \"%s\"\n", connp->conn->client_addr, buf, + request_line, tx->response_status_number, tx->response_message_len, + referer, user_agent); + + free(referer); + free(user_agent); + free(request_line); +} + +static int run_file(char *filename, htp_cfg_t *cfg) { + htp_connp_t *connp; + + fprintf(stdout, "Running file %s", filename); + + int rc = tcpick_run_file(filename, cfg, &connp); + if (rc < 0) { + if (connp != NULL) { + htp_log_t *last_error = htp_connp_get_last_error(connp); + if (last_error != NULL) { + printf(" -- failed: %s\n", last_error->msg); + } else { + printf(" -- failed: ERROR NOT AVAILABLE\n"); + } + + return 0; + } else { + return -1; + } + } else { + printf(" -- %zu transaction(s)\n", htp_list_size(connp->conn->transactions)); + + for (int i = 0, n = htp_list_size(connp->conn->transactions); i < n; i++) { + htp_tx_t *tx = htp_list_get(connp->conn->transactions, i); + + printf(" "); + print_tx(connp, tx); + } + + printf("\n"); + + htp_connp_destroy_all(connp); + + return 1; + } +} + +static int run_directory(char *dirname, htp_cfg_t *cfg) { + struct dirent *entry; + char buf[1025]; + DIR *d = opendir(dirname); + + if (d == NULL) { + printf("Failed to open directory: %s\n", dirname); + return -1; + } + + while ((entry = readdir(d)) != NULL) { + if (strncmp(entry->d_name, "tcpick", 6) == 0) { + strncpy(buf, dirname, 1024); + strncat(buf, "/", 1024 - strlen(buf)); + strncat(buf, entry->d_name, 1024 - strlen(buf)); + + // fprintf(stderr, "Filename: %s\n", buf); + run_file(buf, cfg); + //if (run_file(buf, cfg) <= 0) { + // closedir(d); + // return 0; + //} + } + } + + closedir(d); + + return 1; +} |