summaryrefslogtreecommitdiffstats
path: root/examples/mod_libhtp/mod_libhtp.c
blob: 07a779ce05d75b41e40411843d42364e0723aa0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/***************************************************************************
 * 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.
 ***************************************************************************/

#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "ap_config.h"

#include "htp.h"
#include "htp_transaction.h"

module AP_MODULE_DECLARE_DATA libhtp_module;

// XXX Handle all allocation failures
    
static int convert_method_number(int method_number) {
    // We can cheat here because LibHTP reuses Apache's
    // method identifiers. But we really shouldn't.
    if ((method_number >= 0)&&(method_number <= 26)) {
        return method_number;
    }
    
    // TODO Decouple this functions from Apache's internals.

    return HTP_M_UNKNOWN;
}

static int convert_protocol_number(int protocol_number) {
    // In Apache, 1.1 is stored as 1001. In LibHTP,
    // the same protocol number is stored as 101.
    return (protocol_number / 1000) * 100 + (protocol_number % 1000);
}

static apr_status_t transaction_cleanup(htp_tx_t *tx) {
    htp_tx_destroy(tx);
    return APR_SUCCESS;
}

static int libhtp_post_read_request(request_rec *r) {
    htp_connp_t *connp = ap_get_module_config(r->connection->conn_config, &libhtp_module);
    if (connp == NULL) return DECLINED;

    // Create a new LibHTP transaction
    htp_tx_t *tx = htp_connp_tx_create(connp);
    if (tx == NULL) return DECLINED;

    // Request begins
    htp_tx_state_request_start(tx);

    // Populate request line
    htp_tx_req_set_method_c(tx, r->method, HTP_ALLOC_REUSE);
    htp_tx_req_set_method_number(tx, convert_method_number(r->method_number));
    htp_tx_req_set_uri_c(tx, r->uri, HTP_ALLOC_REUSE);
    htp_tx_req_set_query_string_c(tx, r->args, HTP_ALLOC_REUSE);
    htp_tx_req_set_protocol_c(tx, r->protocol, HTP_ALLOC_REUSE);
    htp_tx_req_set_protocol_number(tx, convert_protocol_number(r->proto_num));
    htp_tx_req_set_protocol_0_9(tx, r->assbackwards);

    // Request line available
    htp_tx_state_request_line(tx);

    // Populate request headers
    size_t i;
    const apr_array_header_t *arr = apr_table_elts(r->headers_in);
    const apr_table_entry_t *te = (apr_table_entry_t *) arr->elts;
    for (i = 0; i < arr->nelts; i++) {
        htp_tx_req_set_header_c(tx, te[i].key, te[i].val, HTP_ALLOC_REUSE);
    }

    // Request headers available
    htp_tx_state_request_headers(tx);

    // Attach LibHTP's transaction to Apache's request
    ap_set_module_config(r->request_config, &libhtp_module, tx);
    apr_pool_cleanup_register(r->pool, (void *)tx,
            (apr_status_t (*)(void *))transaction_cleanup, apr_pool_cleanup_null);

    return DECLINED;
}

static apr_status_t connection_cleanup(htp_connp_t *connp) {
    htp_config_destroy(connp->cfg);
    htp_connp_destroy(connp);
    
    return APR_SUCCESS;
}

static int libhtp_pre_connection(conn_rec *c, void *csd) {
    // Configuration; normally you'd read the configuration from
    // a file, or some other type of storage, but, because this is
    // just an example, we have it hard-coded.
    htp_cfg_t *cfg = htp_config_create();
    if (cfg == NULL) return OK;
    htp_config_set_server_personality(cfg, HTP_SERVER_APACHE_2_2);
    htp_config_register_urlencoded_parser(cfg);
    htp_config_register_multipart_parser(cfg);

    // Connection parser
    htp_connp_t *connp = htp_connp_create(cfg);
    if (connp == NULL) {
        htp_config_destroy(cfg);
        free(connp);
        return OK;
    }

    // Open connection
    htp_connp_open(connp, c->remote_ip, /* XXX remote port */ 0, c->local_ip, /* XXX local port */0, NULL);

    ap_set_module_config(c->conn_config, &libhtp_module, connp);
    apr_pool_cleanup_register(c->pool, (void *)connp,
            (apr_status_t (*)(void *))connection_cleanup, apr_pool_cleanup_null);

    return OK;
}

static void libhtp_register_hooks(apr_pool_t *p) {
    ap_hook_pre_connection(libhtp_pre_connection, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_post_read_request(libhtp_post_read_request, NULL, NULL, APR_HOOK_MIDDLE);
}

/* Dispatch list for API hooks */
module AP_MODULE_DECLARE_DATA libhtp_module = {
    STANDARD20_MODULE_STUFF,
    NULL, /* create per-dir    config structures */
    NULL, /* merge  per-dir    config structures */
    NULL, /* create per-server config structures */
    NULL, /* merge  per-server config structures */
    NULL, /* table of config file commands       */
    libhtp_register_hooks /* register hooks                      */
};