9 #include "inet_ntop_cache.h"
18 * we indent to implement all features the mod_evasive from apache has
20 * - limit of connections per IP
21 * - provide a list of block-listed ip/networks (no access)
22 * - provide a white-list of ips/network which is not affected by the limit
23 * (hmm, conditionals might be enough)
24 * - provide a bandwidth limiter per IP
27 * - w1zzard@techpowerup.com
31 unsigned short max_conns
;
32 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;
67 free(p
->config_storage
);
75 SETDEFAULTS_FUNC(mod_evasive_set_defaults
) {
79 config_values_t cv
[] = {
80 { "evasive.max-conns-per-ip", NULL
, T_CONFIG_SHORT
, T_CONFIG_SCOPE_CONNECTION
}, /* 0 */
81 { "evasive.silent", NULL
, T_CONFIG_BOOLEAN
, T_CONFIG_SCOPE_CONNECTION
}, /* 1 */
82 { NULL
, NULL
, T_CONFIG_UNSET
, T_CONFIG_SCOPE_UNSET
}
85 p
->config_storage
= calloc(1, srv
->config_context
->used
* sizeof(plugin_config
*));
87 for (i
= 0; i
< srv
->config_context
->used
; i
++) {
88 data_config
const* config
= (data_config
const*)srv
->config_context
->data
[i
];
91 s
= calloc(1, sizeof(plugin_config
));
95 cv
[0].destination
= &(s
->max_conns
);
96 cv
[1].destination
= &(s
->silent
);
98 p
->config_storage
[i
] = s
;
100 if (0 != config_insert_values_global(srv
, config
->value
, cv
, i
== 0 ? T_CONFIG_SCOPE_SERVER
: T_CONFIG_SCOPE_CONNECTION
)) {
101 return HANDLER_ERROR
;
105 return HANDLER_GO_ON
;
110 static int mod_evasive_patch_connection(server
*srv
, connection
*con
, plugin_data
*p
) {
112 plugin_config
*s
= p
->config_storage
[0];
117 /* skip the first, the global context */
118 for (i
= 1; i
< srv
->config_context
->used
; i
++) {
119 data_config
*dc
= (data_config
*)srv
->config_context
->data
[i
];
120 s
= p
->config_storage
[i
];
122 /* condition didn't match */
123 if (!config_check_cond(srv
, con
, dc
)) continue;
126 for (j
= 0; j
< dc
->value
->used
; j
++) {
127 data_unset
*du
= dc
->value
->data
[j
];
129 if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
131 } else if (buffer_is_equal_string(du
->key
, CONST_STR_LEN("evasive.silent"))) {
141 URIHANDLER_FUNC(mod_evasive_uri_handler
) {
142 plugin_data
*p
= p_d
;
143 size_t conns_by_ip
= 0;
146 if (buffer_is_empty(con
->uri
.path
)) return HANDLER_GO_ON
;
148 mod_evasive_patch_connection(srv
, con
, p
);
150 /* no limit set, nothing to block */
151 if (p
->conf
.max_conns
== 0) return HANDLER_GO_ON
;
153 switch (con
->dst_addr
.plain
.sa_family
) {
159 default: /* Address family not supported */
160 return HANDLER_GO_ON
;
163 for (j
= 0; j
< srv
->conns
->used
; j
++) {
164 connection
*c
= srv
->conns
->ptr
[j
];
166 /* check if other connections are already actively serving data for the same IP
167 * we can only ban connections which are already behind the 'read request' state
169 if (c
->dst_addr
.plain
.sa_family
!= con
->dst_addr
.plain
.sa_family
) continue;
170 if (c
->state
<= CON_STATE_REQUEST_END
) continue;
172 switch (con
->dst_addr
.plain
.sa_family
) {
174 if (c
->dst_addr
.ipv4
.sin_addr
.s_addr
!= con
->dst_addr
.ipv4
.sin_addr
.s_addr
) continue;
178 if (0 != memcmp(c
->dst_addr
.ipv6
.sin6_addr
.s6_addr
, con
->dst_addr
.ipv6
.sin6_addr
.s6_addr
, 16)) continue;
181 default: /* Address family not supported, should never be reached */
186 if (conns_by_ip
> p
->conf
.max_conns
) {
187 if (!p
->conf
.silent
) {
188 log_error_write(srv
, __FILE__
, __LINE__
, "ss",
189 inet_ntop_cache_get_ip(srv
, &(con
->dst_addr
)),
190 "turned away. Too many connections.");
193 con
->http_status
= 403;
195 return HANDLER_FINISHED
;
199 return HANDLER_GO_ON
;
203 int mod_evasive_plugin_init(plugin
*p
);
204 int mod_evasive_plugin_init(plugin
*p
) {
205 p
->version
= LIGHTTPD_VERSION_ID
;
206 p
->name
= buffer_init_string("evasive");
208 p
->init
= mod_evasive_init
;
209 p
->set_defaults
= mod_evasive_set_defaults
;
210 p
->handle_uri_clean
= mod_evasive_uri_handler
;
211 p
->cleanup
= mod_evasive_free
;