MINOR: Add Mod Defender integration as contrib

This is a service that talks SPOE protocol and uses the Mod Defender (a
NAXSI clone) functionality to detect HTTP attacks. It returns a HTTP
status code to indicate whether the request is suspicious or not, based on
NAXSI rules. The value of the returned code can be used in HAProxy rules
to determine if the HTTP request should be blocked/rejected.
This commit is contained in:
Dragan Dosen 2017-06-02 12:03:16 +02:00 committed by Willy Tarreau
parent 9ac143b607
commit 59bb97a192
8 changed files with 4508 additions and 0 deletions

View File

@ -0,0 +1,50 @@
DESTDIR =
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
CC = gcc
LD = $(CC)
CXX = g++
ifeq ($(MOD_DEFENDER_SRC),)
MOD_DEFENDER_SRC := ./mod_defender_src
endif
ifeq ($(APACHE2_INC),)
APACHE2_INC := /usr/include/apache2
endif
ifeq ($(APR_INC),)
APR_INC := /usr/include/apr-1.0
endif
CFLAGS = -g -Wall -pthread
LDFLAGS = -lpthread -levent -levent_pthreads -lapr-1 -laprutil-1 -lstdc++
INCS += -I../../include -I../../ebtree -I$(MOD_DEFENDER_SRC) -I$(APACHE2_INC) -I$(APR_INC)
LIBS =
CXXFLAGS = -g -std=gnu++11
CXXINCS += -I$(MOD_DEFENDER_SRC) -I$(MOD_DEFENDER_SRC)/deps -I$(APACHE2_INC) -I$(APR_INC)
SRCS = standalone.o spoa.o defender.o \
$(wildcard $(MOD_DEFENDER_SRC)/deps/libinjection/*.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
CXXSRCS = $(wildcard $(MOD_DEFENDER_SRC)/*.cpp)
CXXOBJS = $(patsubst %.cpp, %.o, $(CXXSRCS))
defender: $(OBJS) $(CXXOBJS)
$(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
install: defender
install defender $(DESTDIR)$(BINDIR)
clean:
rm -f defender $(OBJS) $(CXXOBJS)
%.o: %.c
$(CC) $(CFLAGS) $(INCS) -c -o $@ $<
%.o: %.cpp
$(CXX) $(CXXFLAGS) $(CXXINCS) -c -o $@ $<

159
contrib/mod_defender/README Normal file
View File

@ -0,0 +1,159 @@
--------------------------
Mod Defender for HAProxy
--------------------------
This is a service that talks SPOE protocol and uses the Mod Defender
(https://github.com/VultureProject/mod_defender) functionality to detect
HTTP attacks. It returns a HTTP status code to indicate whether the request
is suspicious or not, based on NAXSI rules. The value of the returned code
can be used in HAProxy rules to determine if the HTTP request should be
blocked/rejected.
Unlike ModSecurity, Mod Defender is a whitelist based WAF (everything is
disallowed, unless there are rules saying otherwise). It's a partial
replication of NAXSI and it uses NAXSI compatible rules configuration
format.
1) How to build it
------------------
Required packages :
* Mod Defender source (https://github.com/VultureProject/mod_defender)
* Asynchronous event notification library and headers (libevent)
* Apache 2 (>= 2.4) development headers
* APR library and headers
* GNU C (gcc) and C++ (g++) >= 4.9
* GNU Standard C++ Library v3 (libstdc++)
* GNU Make
Compile the source :
$ make MOD_DEFENDER_SRC=/path/to/mod_defender_src
2) Configuration
----------------
Download the Naxsi core rules file :
$ wget -O /path/to/core.rules \
https://raw.githubusercontent.com/nbs-system/naxsi/master/naxsi_config/naxsi_core.rules
Create the Mod Defender configuration file. For example :
# Defender toggle
Defender On
# Match log path
MatchLog /path/to/defender_match.log
# JSON Match log path
JSONMatchLog /path/to/defender_json_match.log
# Request body limit
RequestBodyLimit 8388608
# Learning mode toggle
LearningMode Off
# Extensive Learning log toggle
ExtensiveLog Off
# Libinjection SQL toggle
LibinjectionSQL On
# Libinjection XSS toggle
LibinjectionXSS On
# Rules
Include /path/to/core.rules
# Score action
CheckRule "$SQL >= 8" BLOCK
CheckRule "$RFI >= 8" BLOCK
CheckRule "$TRAVERSAL >= 4" BLOCK
CheckRule "$EVADE >= 4" BLOCK
CheckRule "$XSS >= 8" BLOCK
CheckRule "$UPLOAD >= 8" BLOCK
# Whitelists
# ....
Next step is to configure the SPOE for use with the Mod Defender service.
Example configuration (args elements order is important) :
[mod_defender]
spoe-agent mod-defender-agent
messages check-request
option var-prefix defender
timeout hello 100ms
timeout idle 30s
timeout processing 15ms
use-backend spoe-mod-defender
spoe-message check-request
args src unique-id method path query req.ver req.hdrs_bin req.body
event on-frontend-http-request
The engine is in the scope "mod_defender". To enable it, you must set the
following line in a frontend/listener section :
frontend my_frontend
...
filter spoe engine mod_defender config /path/to/spoe-mod-defender.conf
...
Also, we must define the "spoe-mod-defender" backend in HAProxy configuration :
backend spoe-mod-defender
mode tcp
balance roundrobin
timeout connect 5s
timeout server 3m
server defender1 127.0.0.1:12345
The Mod Defender status is returned in a variable "sess.defender.status" --
it contains the returned HTTP status code. The request is considered
malicious if the variable contains value greater than zero.
The following rule can be used to reject all suspicious HTTP requests :
http-request deny if { var(sess.defender.status) -m int gt 0 }
3) Start the service
--------------------
To start the service, you need to use "defender" binary :
$ ./defender -h
Usage : ./defender [OPTION]...
-h Print this message
-f <config-file> Mod Defender configuration file
-l <log-file> Mod Defender log file
-d Enable the debug mode
-m <max-frame-size> Specify the maximum frame size (default : 16384)
-p <port> Specify the port to listen on (default : 12345)
-n <num-workers> Specify the number of workers (default : 10)
-c <capability> Enable the support of the specified capability
-t <time> Set a delay to process a message (default: 0)
The value is specified in milliseconds by default,
but can be in any other unit if the number is suffixed
by a unit (us, ms, s)
Supported capabilities: fragmentation, pipelining, async
Example:
$ ./defender -n 4 -f /path/to/mod_defender.conf -d -l /path/to/error.log
4) Known bugs and limitations
-----------------------------
In its current state, the module is limited by haproxy to the analysis of
the first buffer. One workaround may consist in significantly increasing
haproxy's buffer size.

View File

@ -0,0 +1,633 @@
/*
* Mod Defender for HAProxy
*
* Copyright 2017 HAProxy Technologies, Dragan Dosen <ddosen@haproxy.com>
*
* Mod Defender
* Copyright (c) 2017 Annihil (https://github.com/VultureProject/mod_defender)
*
* Parts of code based on Apache HTTP Server source
* Copyright 2015 The Apache Software Foundation (http://www.apache.org/)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 3 of the License, or (at your option) any later version.
*
*/
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
#include <common/defaults.h>
#include <common/standard.h>
#include <common/chunk.h>
#include <common/time.h>
#include <proto/spoe.h>
#include <http_core.h>
#include <http_main.h>
#include <http_log.h>
#include <http_request.h>
#include <apr_pools.h>
#include <apr_strings.h>
#include "spoa.h"
#include "standalone.h"
#include "defender.h"
#define DEFENDER_NAME "defender"
#define DEFENDER_INPUT_FILTER "DEFENDER_IN"
#define DEFENDER_DEFAULT_UNIQUE_ID "unique_id"
#define DEFENDER_BRIGADE_REQUEST "defender-brigade-request"
extern module AP_MODULE_DECLARE_DATA defender_module;
DECLARE_HOOK(int,post_config,(apr_pool_t *pconf,apr_pool_t *plog, apr_pool_t *ptemp,server_rec *s))
DECLARE_HOOK(int,fixups,(request_rec *r))
DECLARE_HOOK(int,header_parser,(request_rec *r))
char *defender_name = DEFENDER_NAME;
const char *defender_argv[] = { DEFENDER_NAME, NULL };
const char *defender_unknown_hostname = "";
void *defender_module_config = NULL;
static server_rec *server = NULL;
apr_pool_t *defender_pool = NULL;
char hostname[MAX_HOSTNAME_LEN];
char defender_cwd[MAXPATHLEN];
static apr_status_t defender_bucket_read(apr_bucket *b, const char **str,
apr_size_t *len, apr_read_type_e block);
static void defender_bucket_destroy(void *data);
static const apr_bucket_type_t apr_bucket_type_defender = {
"defender", 8, APR_BUCKET_DATA,
defender_bucket_destroy,
defender_bucket_read,
apr_bucket_setaside_noop,
apr_bucket_shared_split,
apr_bucket_shared_copy
};
struct apr_bucket_defender {
apr_bucket_refcount refcount;
struct chunk buf;
};
static apr_status_t defender_bucket_read(apr_bucket *b, const char **str,
apr_size_t *len, apr_read_type_e block)
{
struct apr_bucket_defender *d = b->data;
*str = d->buf.str;
*len = d->buf.len;
return APR_SUCCESS;
}
static void defender_bucket_destroy(void *data)
{
struct apr_bucket_defender *d = data;
if (apr_bucket_shared_destroy(d))
apr_bucket_free(d);
}
static apr_bucket *defender_bucket_make(apr_bucket *b, const struct chunk *buf)
{
struct apr_bucket_defender *d;
d = apr_bucket_alloc(sizeof(*d), b->list);
d->buf.str = buf->str;
d->buf.len = buf->len;
d->buf.size = 0;
b = apr_bucket_shared_make(b, d, 0, buf->len);
b->type = &apr_bucket_type_defender;
return b;
}
static apr_bucket *defender_bucket_create(const struct chunk *buf,
apr_bucket_alloc_t *list)
{
apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
APR_BUCKET_INIT(b);
b->free = apr_bucket_free;
b->list = list;
return defender_bucket_make(b, buf);
}
static void defender_logger(int level, char *str)
{
LOG(&null_worker, "%s", str);
}
static char *defender_strdup(apr_pool_t *pool, const char *src, uint64_t len)
{
char *dst;
if (!(dst = apr_pcalloc(pool, len + 1)))
return NULL;
memcpy(dst, src, len);
dst[len] = '\0';
return dst;
}
static char *defender_printf(apr_pool_t *pool, const char *fmt, ...)
{
va_list argp;
char *dst;
int len;
va_start(argp, fmt);
len = vsnprintf(NULL, 0, fmt, argp);
if (len < 0)
return NULL;
va_end(argp);
if (!(dst = apr_pcalloc(pool, len + 1)))
return NULL;
va_start(argp, fmt);
len = vsnprintf(dst, len + 1, fmt, argp);
va_end(argp);
return dst;
}
static char *defender_addr2str(apr_pool_t *pool, struct sample *addr)
{
sa_family_t family;
const void *src;
char *dst;
switch (addr->data.type) {
case SMP_T_IPV4:
src = &addr->data.u.ipv4;
family = AF_INET;
break;
case SMP_T_IPV6:
src = &addr->data.u.ipv6;
family = AF_INET6;
break;
default:
return NULL;
}
if (!(dst = apr_pcalloc(pool, INET6_ADDRSTRLEN + 1)))
return NULL;
if (inet_ntop(family, src, dst, INET6_ADDRSTRLEN))
return dst;
return NULL;
}
static void defender_pre_config()
{
apr_pool_t *ptemp = NULL;
defender_module.module_index = 0;
defender_module.register_hooks(defender_pool);
apr_pool_create(&ptemp, defender_pool);
run_ap_hook_post_config(defender_pool, defender_pool, ptemp, server);
apr_pool_destroy(ptemp);
}
static const char *defender_read_config(const char *file)
{
apr_pool_t *ptemp = NULL;
const char *err;
const char *fullname;
defender_module_config = defender_module.create_dir_config(defender_pool, "/");
if (defender_module_config == NULL) {
return "cannot allocate space for the configuration structure";
}
apr_pool_create(&ptemp, defender_pool);
fullname = ap_server_root_relative(ptemp, file);
err = read_module_config(server, defender_module_config,
defender_module.cmds,
defender_pool, ptemp, fullname);
apr_pool_destroy(ptemp);
return err;
}
static void defender_post_config()
{
apr_pool_t *ptemp = NULL;
apr_pool_create(&ptemp, defender_pool);
run_ap_hook_post_config(defender_pool, defender_pool, ptemp, server);
apr_pool_destroy(ptemp);
}
static const char *defender_set_logger(const char *file)
{
char *logname;
logger = defender_logger;
if (file == NULL)
return NULL;
logname = ap_server_root_relative(defender_pool, file);
if (apr_file_open(&server->error_log, logname,
APR_APPEND | APR_WRITE | APR_CREATE | APR_LARGEFILE,
APR_OS_DEFAULT, defender_pool) != APR_SUCCESS) {
return apr_pstrcat(defender_pool, "Cannot open log file, ",
logname, NULL);
}
server->error_fname = logname;
return NULL;
}
static apr_status_t defender_input_filter(ap_filter_t *f,
apr_bucket_brigade *new_bb,
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes)
{
apr_bucket_brigade *bb = NULL;
apr_bucket *b = NULL, *a = NULL;
apr_status_t rv;
bb = (apr_bucket_brigade *)apr_table_get(f->r->notes, DEFENDER_BRIGADE_REQUEST);
if (bb == NULL || (bb && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb)))) {
b = apr_bucket_eos_create(f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(new_bb, b);
if (bb == NULL)
return APR_SUCCESS;
}
rv = apr_brigade_partition(bb, readbytes, &a);
if (rv != APR_SUCCESS && rv != APR_INCOMPLETE)
return rv;
b = APR_BRIGADE_FIRST(bb);
while (b != a) {
if (APR_BUCKET_IS_EOS(b))
ap_remove_input_filter(f);
APR_BUCKET_REMOVE(b);
APR_BRIGADE_INSERT_TAIL(new_bb, b);
b = APR_BRIGADE_FIRST(bb);
}
return APR_SUCCESS;
}
static conn_rec *defender_create_conn()
{
conn_rec *c = NULL;
apr_pool_t *ptrans = NULL;
apr_pool_create(&ptrans, defender_pool);
c = apr_pcalloc(ptrans, sizeof(conn_rec));
c->pool = ptrans;
c->local_ip = "127.0.0.1";
c->local_addr = server->addrs->host_addr;
c->local_host = defender_name;
c->client_addr = server->addrs->host_addr;
c->remote_host = defender_name;
c->id = 1;
c->base_server = server;
c->bucket_alloc = apr_bucket_alloc_create(ptrans);
return c;
}
static request_rec *defender_create_request(conn_rec *conn)
{
request_rec *r = NULL;
apr_pool_t *p = NULL;
struct ap_logconf *l;
apr_pool_create(&p, conn->pool);
r = apr_pcalloc(p, sizeof(request_rec));
r->pool = p;
r->connection = conn;
r->server = conn->base_server;
r->headers_in = apr_table_make(p, 25);
r->headers_out = apr_table_make(p, 12);
r->subprocess_env = apr_table_make(p, 25);
r->err_headers_out = apr_table_make(p, 5);
r->notes = apr_table_make(p, 5);
r->request_config = apr_palloc(p, sizeof(void *));
r->per_dir_config = apr_palloc(p, sizeof(void *));
((void **)r->per_dir_config)[0] = defender_module_config;
r->handler = defender_name;
r->parsed_uri.scheme = "http";
r->parsed_uri.is_initialized = 1;
r->parsed_uri.port = 80;
r->parsed_uri.port_str = "80";
r->parsed_uri.fragment = "";
r->input_filters = NULL;
r->output_filters = NULL;
l = apr_pcalloc(p, sizeof(struct ap_logconf));
l->level = APLOG_DEBUG;
r->log = l;
return r;
}
static int defender_process_headers(request_rec *r)
{
return run_ap_hook_header_parser(r);
}
static int defender_process_body(request_rec *r)
{
ap_add_input_filter(DEFENDER_INPUT_FILTER, NULL, r, r->connection);
return run_ap_hook_fixups(r);
}
int defender_init(const char *config_file, const char *log_file)
{
apr_status_t rv;
const char *msg;
if (!config_file) {
LOG(&null_worker, "Mod Defender configuration file not specified.\n");
return 0;
}
apr_initialize();
apr_pool_create(&defender_pool, NULL);
apr_hook_global_pool = defender_pool;
ap_server_root = getcwd(defender_cwd, APR_PATH_MAX);
server = (server_rec *) apr_palloc(defender_pool, sizeof(server_rec));
server->process = apr_palloc(defender_pool, sizeof(process_rec));
server->process->argc = 1;
server->process->argv = defender_argv;
server->process->short_name = defender_name;
server->process->pconf = defender_pool;
server->process->pool = defender_pool;
server->addrs = apr_palloc(defender_pool, sizeof(server_addr_rec));
rv = apr_sockaddr_info_get(&server->addrs->host_addr,
"127.0.0.1", APR_UNSPEC, 0, 0,
defender_pool);
if (rv != APR_SUCCESS) {
LOG(&null_worker, "Mod Defender getaddrinfo failed.\n");
return 0;
}
server->path = "/";
server->pathlen = strlen(server->path);
server->port = 0;
server->server_admin = defender_name;
server->server_scheme = "";
server->error_fname = NULL;
server->error_log = NULL;
server->limit_req_line = DEFAULT_LIMIT_REQUEST_LINE;
server->limit_req_fieldsize = DEFAULT_LIMIT_REQUEST_FIELDSIZE;
server->limit_req_fields = DEFAULT_LIMIT_REQUEST_FIELDS;
server->timeout = apr_time_from_sec(DEFAULT_TIMEOUT);
memset(hostname, 0, sizeof(hostname));
gethostname(hostname, sizeof(hostname) - 1);
server->server_hostname = hostname;
server->addrs->host_port = 0;
server->names = server->wild_names = NULL;
server->is_virtual = 0;
server->lookup_defaults = NULL;
server->module_config = NULL;
msg = defender_set_logger(log_file);
if (msg != NULL) {
LOG(&null_worker, "Mod Defender init failed: %s\n", msg);
return 0;
}
ap_register_input_filter(DEFENDER_INPUT_FILTER, defender_input_filter,
NULL, AP_FTYPE_RESOURCE);
defender_pre_config();
msg = defender_read_config(config_file);
if (msg != NULL) {
LOG(&null_worker, "Mod Defender configuration failed: %s\n", msg);
return 0;
}
defender_post_config();
return 1;
}
int defender_process_request(struct worker *worker, struct defender_request *request)
{
struct conn_rec *c = NULL;
struct request_rec *r = NULL;
struct apr_bucket_brigade *bb = NULL;
struct apr_bucket *d = NULL, *e = NULL;
struct chunk *method;
struct chunk *path;
struct chunk *query;
struct chunk *version;
struct chunk *body;
struct defender_header hdr;
char *hdr_ptr, *hdr_end;
const char *ptr;
int status = DECLINED;
if (!(c = defender_create_conn()))
goto out;
if (!(r = defender_create_request(c)))
goto out;
/* request */
r->request_time = apr_time_now();
if (request->clientip.data.type != SMP_T_IPV4 &&
request->clientip.data.type != SMP_T_IPV6)
goto out;
if (!(r->useragent_ip = defender_addr2str(r->pool, &request->clientip)))
goto out;
if (request->id.data.u.str.str && request->id.data.u.str.len > 0) {
apr_table_setn(r->subprocess_env, "UNIQUE_ID",
defender_strdup(r->pool, request->id.data.u.str.str,
request->id.data.u.str.len));
}
else {
apr_table_setn(r->subprocess_env, "UNIQUE_ID",
DEFENDER_DEFAULT_UNIQUE_ID);
}
method = &request->method.data.u.str;
path = &request->path.data.u.str;
query = &request->query.data.u.str;
version = &request->version.data.u.str;
r->method_number = lookup_builtin_method(method->str, method->len);
if (!(r->method = defender_strdup(r->pool, method->str, method->len)))
goto out;
r->unparsed_uri = defender_printf(r->pool, "%.*s%s%.*s",
path->len, path->str,
query->len > 0 ? "?" : "",
query->len, query->str);
if (!r->unparsed_uri)
goto out;
if (!(r->uri = defender_strdup(r->pool, path->str, path->len)))
goto out;
r->parsed_uri.path = r->filename = r->uri;
if (!(r->args = defender_strdup(r->pool, query->str, query->len)))
goto out;
r->parsed_uri.query = r->args;
r->protocol = defender_printf(r->pool, "%s%.*s",
version->len > 0 ? "HTTP/" : "",
version->len, version->str);
if (!r->protocol)
goto out;
r->the_request = defender_printf(r->pool, "%.*s %s%s%s",
method->len, method->str,
r->unparsed_uri,
version->len > 0 ? " " : "",
r->protocol);
if (!r->the_request)
goto out;
/* headers */
if (request->headers.data.type != SMP_T_BIN)
goto misc;
hdr_ptr = request->headers.data.u.str.str;
hdr_end = hdr_ptr + request->headers.data.u.str.len;
while (1) {
memset(&hdr, 0, sizeof(hdr));
if (decode_varint(&hdr_ptr, hdr_end, &hdr.name.len) == -1)
goto out;
if (!(hdr.name.str = defender_strdup(r->pool, hdr_ptr, hdr.name.len)))
goto out;
hdr_ptr += hdr.name.len;
if (hdr_ptr > hdr_end)
goto out;
if (decode_varint(&hdr_ptr, hdr_end, &hdr.value.len) == -1)
goto out;
if (!(hdr.value.str = defender_strdup(r->pool, hdr_ptr, hdr.value.len)))
goto out;
hdr_ptr += hdr.value.len;
if (hdr_ptr > hdr_end)
goto out;
if (!hdr.name.len && !hdr.value.len)
break;
apr_table_setn(r->headers_in, hdr.name.str, hdr.value.str);
}
misc:
r->hostname = apr_table_get(r->headers_in, "Host");
if (!r->hostname)
r->hostname = defender_unknown_hostname;
r->parsed_uri.hostname = (char *)r->hostname;
r->content_type = apr_table_get(r->headers_in, "Content-Type");
r->content_encoding = apr_table_get(r->headers_in, "Content-Encoding");
ptr = apr_table_get(r->headers_in, "Content-Length");
if (ptr)
r->clength = strtol(ptr, NULL, 10);
/* body */
body = &request->body.data.u.str;
bb = apr_brigade_create(r->pool, c->bucket_alloc);
if (bb == NULL)
goto out;
d = defender_bucket_create(body, c->bucket_alloc);
if (d == NULL)
goto out;
APR_BRIGADE_INSERT_TAIL(bb, d);
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(bb, e);
apr_table_setn(r->notes, DEFENDER_BRIGADE_REQUEST, (char *)bb);
/* process */
status = defender_process_headers(r);
if (status == DECLINED)
status = defender_process_body(r);
apr_brigade_cleanup(bb);
/* success */
if (status == DECLINED)
status = OK;
out:
if (r && r->pool) {
apr_table_clear(r->headers_in);
apr_table_clear(r->headers_out);
apr_table_clear(r->subprocess_env);
apr_table_clear(r->err_headers_out);
apr_table_clear(r->notes);
apr_pool_destroy(r->pool);
}
if (c && c->pool) {
apr_bucket_alloc_destroy(c->bucket_alloc);
apr_pool_destroy(c->pool);
}
return status;
}

View File

@ -0,0 +1,42 @@
/*
* Mod Defender for HAProxy
*
* Copyright 2017 HAProxy Technologies, Dragan Dosen <ddosen@haproxy.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 3 of the License, or (at your option) any later version.
*
*/
#ifndef __DEFENDER_H__
#define __DEFENDER_H__
#include <types/sample.h>
struct defender_request {
struct sample clientip;
struct sample id;
struct sample method;
struct sample path;
struct sample query;
struct sample version;
struct sample headers;
struct sample body;
};
struct defender_header {
struct {
char *str;
uint64_t len;
} name;
struct {
char *str;
uint64_t len;
} value;
};
int defender_init(const char *config_file, const char *log_file);
int defender_process_request(struct worker *worker, struct defender_request *request);
#endif /* __DEFENDER_H__ */

1886
contrib/mod_defender/spoa.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
/*
* Mod Defender for HAProxy
*
* Copyright 2017 HAProxy Technologies, Dragan Dosen <ddosen@haproxy.com>
*
* Based on "A Random IP reputation service acting as a Stream Processing Offload Agent"
* Copyright 2016 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 3 of the License, or (at your option) any later version.
*
*/
#ifndef __SPOA_H__
#define __SPOA_H__
#include <sys/time.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/thread.h>
#define LOG(worker, fmt, args...) \
do { \
struct timeval now; \
\
gettimeofday(&now, NULL); \
fprintf(stderr, "%ld.%06ld [%02d] " fmt "\n", \
now.tv_sec, now.tv_usec, (worker)->id, ##args); \
} while (0)
struct worker {
pthread_t thread;
int id;
struct event_base *base;
struct event *monitor_event;
struct list engines;
unsigned int nbclients;
struct list clients;
struct list frames;
};
extern struct worker null_worker;
#endif /* __SPOA_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
/*
* Mod Defender for HAProxy
*
* Support for the Mod Defender code on non-Apache platforms.
*
* Copyright 2017 HAProxy Technologies, Dragan Dosen <ddosen@haproxy.com>
*
* Parts of code based on Apache HTTP Server source
* Copyright 2015 The Apache Software Foundation (http://www.apache.org/)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 3 of the License, or (at your option) any later version.
*
*/
#ifndef __STANDALONE_H__
#define __STANDALONE_H__
#include <http_core.h>
#include <http_main.h>
#include <http_config.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
|| (before_this)->frec->ftype > (f)->frec->ftype \
|| (before_this)->r != (f)->r)
#define DECLARE_EXTERNAL_HOOK(ns,link,ret,name,args) \
ns##_HOOK_##name##_t *run_##ns##_hook_##name = NULL; \
link##_DECLARE(void) ns##_hook_##name(ns##_HOOK_##name##_t *pf, \
const char * const *aszPre, \
const char * const *aszSucc, int nOrder) \
{ \
run_##ns##_hook_##name = pf; \
}
#define DECLARE_HOOK(ret,name,args) \
DECLARE_EXTERNAL_HOOK(ap,AP,ret,name,args)
#define UNKNOWN_METHOD (-1)
extern void (*logger)(int level, char *str);
extern const char *read_module_config(server_rec *s, void *mconfig,
const command_rec *cmds,
apr_pool_t *p, apr_pool_t *ptemp,
const char *filename);
extern int lookup_builtin_method(const char *method, apr_size_t len);
#endif /* __STANDALONE_H__ */