6 #include "http_header.h"
17 * we indent to implement all features the mod_evasive from apache has
19 * - limit of connections per IP
20 * - provide a list of block-listed ip/networks (no access)
21 * - provide a white-list of ips/network which is not affected by the limit
22 * (hmm, conditionals might be enough)
23 * - provide a bandwidth limiter per IP
26 * - w1zzard@techpowerup.com
30 unsigned short max_conns
;
31 unsigned short silent
;
38 plugin_config
**config_storage
;
43 INIT_FUNC(mod_evasive_init
) {
46 p
= calloc(1, sizeof(*p
));
51 FREE_FUNC(mod_evasive_free
) {
56 if (!p
) return HANDLER_GO_ON
;
58 if (p
->config_storage
) {
60 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
61 plugin_config
*s
= p
->config_storage
[i
];
63 if (NULL
== s
) continue;
65 buffer_free(s
->location
);
69 free(p
->config_storage
);
77 SETDEFAULTS_FUNC(mod_evasive_set_defaults
) {
81 config_values_t cv
[] = {
82 { "evasive.max-conns-per-ip", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 0 */
83 { "evasive.silent", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 1 */
84 { "evasive.location", NULL
, T_CONFIG_STRING
, T_CONFIG_SCOPE_CONNECTION
}, /* 2 */
85 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
88 p
->config_storage
= calloc(srv
->config_context
->used
, sizeof(plugin_config
*));
90 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
91 data_config
const* config
= (data_config
const*)srv
->config_context
->data
[i
];
94 s
= calloc(1, sizeof(plugin_config
));
97 s
->location
= buffer_init();
99 cv
[0].destination
= &(s
->max_conns
);
100 cv
[1].destination
= &(s
->silent
);
101 cv
[2].destination
= s
->location
;
103 p
->config_storage
[i
] = s
;
105 if (0 != config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
106 return HANDLER_ERROR
;
110 return HANDLER_GO_ON
;
115 static int mod_evasive_patch_connection(server
*srv
, connection
*con
, plugin_data
*p
) {
117 plugin_config
*s
= p
->config_storage
[0];
123 /* skip the first, the global context */
124 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
125 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
126 s
= p
->config_storage
[i
];
128 /* condition didn't match */
129 if (!config_check_cond(srv
, con
, dc
)) continue;
132 for (j
= 0; j
< dc
->value
->used
; j
++) {
133 data_unset
*du
= dc
->value
->data
[j
];
135 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
137 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("evasive.silent"))) {
139 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("evasive.location"))) {
149 URIHANDLER_FUNC(mod_evasive_uri_handler
) {
150 plugin_data
*p
= p_d
;
151 size_t conns_by_ip
= 0;
154 if (buffer_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
156 mod_evasive_patch_connection(srv
, con
, p
);
158 /* no limit set, nothing to block */
159 if (p
->conf
.max_conns
== 0) return HANDLER_GO_ON
;
161 for (j
= 0; j
< srv
->conns
->used
; j
++) {
162 connection
*c
= srv
->conns
->ptr
[j
];
164 /* check if other connections are already actively serving data for the same IP
165 * we can only ban connections which are already behind the 'read request' state
167 if (c
->state
<= CON_STATE_REQUEST_END
) continue;
169 if (!sock_addr_is_addr_eq(&c
->dst_addr
, &con
->dst_addr
)) continue;
172 if (conns_by_ip
> p
->conf
.max_conns
) {
173 if (!p
->conf
.silent
) {
174 log_error_write(srv
, __FILE__
, __LINE__
, "bs",
176 "turned away. Too many connections.");
179 if (!buffer_is_empty(p
->conf
.location
)) {
180 http_header_response_set(con
, HTTP_HEADER_LOCATION
, CONST_STR_LEN("Location"), CONST_BUF_LEN(p
->conf
.location
));
181 con
->http_status
= 302;
182 con
->file_finished
= 1;
184 con
->http_status
= 403;
187 return HANDLER_FINISHED
;
191 return HANDLER_GO_ON
;
195 int mod_evasive_plugin_init(plugin
*p
);
196 int mod_evasive_plugin_init(plugin
*p
) {
197 p
->version
= LIGHTTPD_VERSION_ID
;
198 p
->name
= buffer_init_string("evasive");
200 p
->init
= mod_evasive_init
;
201 p
->set_defaults
= mod_evasive_set_defaults
;
202 p
->handle_uri_clean
= mod_evasive_uri_handler
;
203 p
->cleanup
= mod_evasive_free
;