[MEDIUM] added the "reqtarpit" and "reqitarpit" features
It is now possible to tarpit connections based on regex matches.
The tarpit timeout is equal to the contimeout. A 500 server error
response is faked, and the logs show the status flags as "PT" which
indicate the connection has been tarpitted.
diff --git a/src/proto_http.c b/src/proto_http.c
index aa64e21..0b0ce73 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -451,6 +451,17 @@
*/
tv_eternity(&req->rex);
+
+ /* When a connection is tarpitted, we use the queue timeout for the
+ * tarpit delay, which currently happens to be the server's connect
+ * timeout. If unset, then set it to zero because we really want it
+ * to expire at one moment.
+ */
+ if (t->flags & SN_CLTARPIT) {
+ tv_delayfrom(&req->cex, &now,
+ t->proxy->contimeout ? t->proxy->contimeout : 0);
+ }
+
goto process_data;
}
@@ -637,23 +648,27 @@
if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
switch (exp->action) {
case ACT_ALLOW:
- if (!(t->flags & SN_CLDENY))
+ if (!(t->flags & (SN_CLDENY | SN_CLTARPIT)))
t->flags |= SN_CLALLOW;
break;
case ACT_REPLACE:
- if (!(t->flags & SN_CLDENY)) {
+ if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
int len = exp_replace(trash, req->h, exp->replace, pmatch);
ptr += buffer_replace2(req, req->h, ptr, trash, len);
}
break;
case ACT_REMOVE:
- if (!(t->flags & SN_CLDENY))
+ if (!(t->flags & (SN_CLDENY | SN_CLTARPIT)))
delete_header = 1;
break;
case ACT_DENY:
- if (!(t->flags & SN_CLALLOW))
+ if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT)))
t->flags |= SN_CLDENY;
break;
+ case ACT_TARPIT:
+ if (!(t->flags & (SN_CLALLOW | SN_CLDENY)))
+ t->flags |= SN_CLTARPIT;
+ break;
case ACT_PASS: /* we simply don't deny this one */
break;
}
@@ -678,7 +693,7 @@
*/
if (!delete_header &&
(t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
- && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
+ && !(t->flags & (SN_CLDENY|SN_CLTARPIT)) && (ptr >= req->h + 8)
&& (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
char *p1, *p2, *p3, *p4;
char *del_colon, *del_cookie, *colon;
@@ -938,7 +953,7 @@
} /* end of cookie processing on this header */
/* let's look if we have to delete this header */
- if (delete_header && !(t->flags & SN_CLDENY)) {
+ if (delete_header && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
buffer_replace2(req, req->h, req->lr, NULL, 0);
/* WARNING: ptr is not valid anymore, since the header may have
* been deleted or truncated ! */
@@ -1338,6 +1353,27 @@
return 1;
}
else {
+ if (t->flags & SN_CLTARPIT) {
+ /* This connection is being tarpitted. The CLIENT side has
+ * already set the connect expiration date to the right
+ * timeout. We just have to check that it has not expired.
+ */
+ if (tv_cmp2_ms(&req->cex, &now) > 0)
+ return 0;
+
+ /* We will set the queue timer to the time spent, just for
+ * logging purposes. We fake a 500 server error, so that the
+ * attacker will not suspect his connection has been tarpitted.
+ * It will not cause trouble to the logs because we can exclude
+ * the tarpitted connections by filtering on the 'PT' status flags.
+ */
+ tv_eternity(&req->cex);
+ t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
+ srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
+ 500, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
+ return 1;
+ }
+
/* Right now, we will need to create a connection to the server.
* We might already have tried, and got a connection pending, in
* which case we will not do anything till it's pending. It's up