mirror of https://github.com/OISF/suricata
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			275 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
			
		
		
	
	
			275 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			C
		
	
/*
 | 
						|
 * LibHTP (http://www.libhtp.org)
 | 
						|
 * Copyright 2009,2010 Ivan Ristic <ivanr@webkreator.com>
 | 
						|
 *
 | 
						|
 * LibHTP is an open source product, released under terms of the General Public Licence
 | 
						|
 * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text
 | 
						|
 * of the license.
 | 
						|
 *
 | 
						|
 * In addition, there is a special exception that allows LibHTP to be freely
 | 
						|
 * used with any OSI-approved open source licence. Please refer to the file
 | 
						|
 * LIBHTP_LICENSING_EXCEPTION for the full text of the exception.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "htp.h"
 | 
						|
 | 
						|
// NOTE The parser contains a lot of duplicated code. That is on purpose.
 | 
						|
//
 | 
						|
//      Within the request parser alone there are several states in which
 | 
						|
//      bytes are copied into the line buffer and lines are processed one at a time.
 | 
						|
//      This code could be made more elegant by adding a new line-reading state along
 | 
						|
//      with a what-fn-to-invoke-to-handle-line pointer.
 | 
						|
//
 | 
						|
//      Furthermore, the entire request parser is terribly similar to the response parser.
 | 
						|
//      It is imaginable that a single parser could handle both.
 | 
						|
//
 | 
						|
//      After some thought, I decided not to make any changes (at least not for the time
 | 
						|
//      being). State-based parsers are sometimes difficult to understand. I remember trying
 | 
						|
//      to figure one once and I had a hard time following the logic because each function
 | 
						|
//      was small and did exactly one thing. There was jumping all around. You could probably
 | 
						|
//      say that it was elegant, but I saw it as difficult to understand, verify and maintain.
 | 
						|
//
 | 
						|
//      Thus, I am keeping this inelegant but quite straightforward parser with duplicated code,
 | 
						|
//      mostly for the sake of maintenance.
 | 
						|
//
 | 
						|
//      For the time being, anyway. I will review at a later time.
 | 
						|
 | 
						|
/**
 | 
						|
 * Clears an existing parser error, if any.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 */
 | 
						|
void htp_connp_clear_error(htp_connp_t *connp) {
 | 
						|
    connp->last_error = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Closes the connection associated with the supplied parser.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 * @param timestamp
 | 
						|
 */
 | 
						|
void htp_connp_close(htp_connp_t *connp, htp_time_t timestamp) {
 | 
						|
    // Update internal information
 | 
						|
    connp->conn->close_timestamp = timestamp;
 | 
						|
    connp->in_status = STREAM_STATE_CLOSED;
 | 
						|
    connp->out_status = STREAM_STATE_CLOSED;
 | 
						|
 | 
						|
    // Call the parsers one last time, which will allow them
 | 
						|
    // to process the events that depend on stream closure
 | 
						|
    htp_connp_req_data(connp, timestamp, NULL, 0);
 | 
						|
    htp_connp_res_data(connp, timestamp, NULL, 0);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates a new connection parser using the provided configuration. Because
 | 
						|
 * the configuration structure is used directly, in a multithreaded environment
 | 
						|
 * you are not allowed to change the structure, ever. If you have a need to
 | 
						|
 * change configuration on per-connection basis, make a copy of the configuration
 | 
						|
 * structure to go along with every connection parser.
 | 
						|
 *
 | 
						|
 * @param cfg
 | 
						|
 * @return A pointer to a newly created htp_connp_t instance.
 | 
						|
 */
 | 
						|
htp_connp_t *htp_connp_create(htp_cfg_t *cfg) {
 | 
						|
    htp_connp_t *connp = calloc(1, sizeof (htp_connp_t));
 | 
						|
    if (connp == NULL) return NULL;
 | 
						|
 | 
						|
    // Use the supplied configuration structure
 | 
						|
    connp->cfg = cfg;
 | 
						|
 | 
						|
    // Create a new connection object
 | 
						|
    connp->conn = htp_conn_create(connp);
 | 
						|
    if (connp->conn == NULL) {
 | 
						|
        free(connp);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    connp->in_status = HTP_OK;
 | 
						|
 | 
						|
    // Request parsing
 | 
						|
 | 
						|
    connp->in_line_size = cfg->field_limit_hard;
 | 
						|
    connp->in_line_len = 0;
 | 
						|
    connp->in_line = malloc(connp->in_line_size);
 | 
						|
    if (connp->in_line == NULL) {
 | 
						|
        htp_conn_destroy(connp->conn);
 | 
						|
        free(connp);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    connp->in_header_line_index = -1;
 | 
						|
    connp->in_state = htp_connp_REQ_IDLE;
 | 
						|
 | 
						|
    // Response parsing
 | 
						|
 | 
						|
    connp->out_line_size = cfg->field_limit_hard;
 | 
						|
    connp->out_line_len = 0;
 | 
						|
    connp->out_line = malloc(connp->out_line_size);
 | 
						|
    if (connp->out_line == NULL) {
 | 
						|
        free(connp->in_line);
 | 
						|
        htp_conn_destroy(connp->conn);
 | 
						|
        free(connp);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    connp->out_header_line_index = -1;
 | 
						|
    connp->out_state = htp_connp_RES_IDLE;
 | 
						|
 | 
						|
    connp->in_status = STREAM_STATE_NEW;
 | 
						|
    connp->out_status = STREAM_STATE_NEW;
 | 
						|
 | 
						|
    return connp;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates a new configuration parser, making a copy of the supplied
 | 
						|
 * configuration structure.
 | 
						|
 *
 | 
						|
 * @param cfg
 | 
						|
 * @return A pointer to a newly created htp_connp_t instance.
 | 
						|
 */
 | 
						|
htp_connp_t *htp_connp_create_copycfg(htp_cfg_t *cfg) {
 | 
						|
    htp_connp_t *connp = htp_connp_create(cfg);
 | 
						|
    if (connp == NULL) return NULL;
 | 
						|
 | 
						|
    connp->cfg = htp_config_copy(cfg);
 | 
						|
    connp->is_cfg_private = 1;
 | 
						|
 | 
						|
    return connp;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Destroys the connection parser and its data structures, leaving
 | 
						|
 * the connection data intact.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 */
 | 
						|
void htp_connp_destroy(htp_connp_t *connp) {
 | 
						|
    if (connp->out_decompressor != NULL) {
 | 
						|
        connp->out_decompressor->destroy(connp->out_decompressor);
 | 
						|
        connp->out_decompressor = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (connp->in_header_line != NULL) {
 | 
						|
        if (connp->in_header_line->line != NULL) {
 | 
						|
            free(connp->in_header_line->line);
 | 
						|
        }
 | 
						|
 | 
						|
        free(connp->in_header_line);
 | 
						|
    }
 | 
						|
 | 
						|
    free(connp->in_line);
 | 
						|
 | 
						|
    if (connp->out_header_line != NULL) {
 | 
						|
        if (connp->out_header_line->line != NULL) {
 | 
						|
            free(connp->out_header_line->line);
 | 
						|
        }
 | 
						|
 | 
						|
        free(connp->out_header_line);
 | 
						|
    }
 | 
						|
 | 
						|
    free(connp->out_line);
 | 
						|
 | 
						|
    // Destroy the configuration structure, but only
 | 
						|
    // if it is our private copy
 | 
						|
    if (connp->is_cfg_private) {
 | 
						|
        htp_config_destroy(connp->cfg);
 | 
						|
    }
 | 
						|
 | 
						|
    free(connp);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Destroys the connection parser, its data structures, as well
 | 
						|
 * as the connection and its transactions.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 */
 | 
						|
void htp_connp_destroy_all(htp_connp_t *connp) {
 | 
						|
    if (connp->conn == NULL) {
 | 
						|
        fprintf(stderr, "HTP: htp_connp_destroy_all was invoked, but conn is NULL\n");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Destroy connection
 | 
						|
    htp_conn_destroy(connp->conn);
 | 
						|
    connp->conn = NULL;
 | 
						|
 | 
						|
    // Destroy everything else
 | 
						|
    htp_connp_destroy(connp);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Retrieve the user data associated with this connection parser.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 * @return User data, or NULL if there isn't any.
 | 
						|
 */
 | 
						|
void *htp_connp_get_data(htp_connp_t *connp) {
 | 
						|
    return connp->user_data;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the last error that occured with this connection parser. Do note, however,
 | 
						|
 * that the value in this field will only be valid immediately after an error condition,
 | 
						|
 * but it is not guaranteed to remain valid if the parser is invoked again.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 * @return A pointer to an htp_log_t instance if there is an error, or NULL
 | 
						|
 *         if there isn't.
 | 
						|
 */
 | 
						|
htp_log_t *htp_connp_get_last_error(htp_connp_t *connp) {
 | 
						|
    return connp->last_error;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Opens connection.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 * @param remote_addr Remote address
 | 
						|
 * @param remote_port Remote port
 | 
						|
 * @param local_addr Local address
 | 
						|
 * @param local_port Local port
 | 
						|
 * @param timestamp
 | 
						|
 */
 | 
						|
void htp_connp_open(htp_connp_t *connp, const char *remote_addr, int remote_port, const char *local_addr, int local_port, htp_time_t timestamp) {
 | 
						|
    if ((connp->in_status != STREAM_STATE_NEW) || (connp->out_status != STREAM_STATE_NEW)) {
 | 
						|
        htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Connection is already open");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (remote_addr != NULL) {
 | 
						|
        connp->conn->remote_addr = strdup(remote_addr);
 | 
						|
        if (connp->conn->remote_addr == NULL) return;
 | 
						|
    }
 | 
						|
 | 
						|
    connp->conn->remote_port = remote_port;
 | 
						|
 | 
						|
    if (local_addr != NULL) {
 | 
						|
        connp->conn->local_addr = strdup(local_addr);
 | 
						|
        if (connp->conn->local_addr == NULL) {
 | 
						|
            if (connp->conn->remote_addr != NULL) {
 | 
						|
                free(connp->conn->remote_addr);
 | 
						|
            }
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    connp->conn->local_port = local_port;
 | 
						|
    connp->conn->open_timestamp = timestamp;
 | 
						|
    connp->in_status = STREAM_STATE_OPEN;
 | 
						|
    connp->out_status = STREAM_STATE_OPEN;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Associate user data with the supplied parser.
 | 
						|
 *
 | 
						|
 * @param connp
 | 
						|
 * @param user_data
 | 
						|
 */
 | 
						|
void htp_connp_set_user_data(htp_connp_t *connp, void *user_data) {
 | 
						|
    connp->user_data = user_data;
 | 
						|
}
 |