Hi William,
diff -c -r ./haproxy-1.3.19/include/common/regex.h
../haproxy-1.3.19/include/common/regex.h
*** ./haproxy-1.3.19/include/common/regex.h Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/include/common/regex.h Sat Aug 1 20:51:33 2009
- 39,44 ****
--- 39,45 ----
#define ACT_PASS 4 /* pass this header without allowing or
denying the request */
#define ACT_TARPIT 5 /* tarpit the connection matching this
request */
#define ACT_SETBE 6 /* switch the backend */
+ #define ACT_DELAY 7 /* delay the connection matching this
request */
struct hdr_exp {
struct hdr_exp *next;
diff -c -r ./haproxy-1.3.19/include/proto/proto_http.h
../haproxy-1.3.19/include/proto/proto_http.h
*** ./haproxy-1.3.19/include/proto/proto_http.h Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/include/proto/proto_http.h Sat Aug 1
22:21:42 2009
- 63,68 ****
--- 63,69 ----
int process_srv_conn(struct session *t);
int http_process_request(struct session *t, struct buffer *req);
int http_process_tarpit(struct session *s, struct buffer *req);
+ int http_process_delay(struct session *s, struct buffer *req);
int http_process_request_body(struct session *s, struct buffer *req);
int process_response(struct session *t);
diff -c -r ./haproxy-1.3.19/include/proto/proxy.h
../haproxy-1.3.19/include/proto/proxy.h
*** ./haproxy-1.3.19/include/proto/proxy.h Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/include/proto/proxy.h Sat Aug 1 22:22:18 2009
- 56,61 ****
--- 56,62 ----
{
proxy->timeout.client = TICK_ETERNITY;
proxy->timeout.tarpit = TICK_ETERNITY;
+ proxy->timeout.delay = TICK_ETERNITY;
proxy->timeout.queue = TICK_ETERNITY;
proxy->timeout.connect = TICK_ETERNITY;
proxy->timeout.server = TICK_ETERNITY;
diff -c -r ./haproxy-1.3.19/include/types/buffers.h
../haproxy-1.3.19/include/types/buffers.h
- ./haproxy-1.3.19/include/types/buffers.h Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/include/types/buffers.h Sat Aug 1 22:19:39 2009
- 108,113 ****
--- 108,114 ----
#define AN_REQ_INSPECT 0x00000001 /* inspect request contents */
#define AN_REQ_HTTP_HDR 0x00000002 /* inspect HTTP request
headers */
#define AN_REQ_HTTP_BODY 0x00000004 /* inspect HTTP request
body */
+ #define AN_REQ_HTTP_DELAY 0x00000006 /* wait for end of HTTP
delay */
#define AN_REQ_HTTP_TARPIT 0x00000008 /* wait for end of HTTP
tarpit */
#define AN_RTR_HTTP_HDR 0x00000010 /* inspect HTTP response
headers */
#define AN_REQ_UNIX_STATS 0x00000020 /* process unix stats
socket request */
diff -c -r ./haproxy-1.3.19/include/types/proto_http.h
../haproxy-1.3.19/include/types/proto_http.h
- ./haproxy-1.3.19/include/types/proto_http.h Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/include/types/proto_http.h Sun Aug 2
00:06:53 2009
- 56,61 ****
--- 56,62 ----
#define TX_SVDENY 0x00000004 /* a server header matches a
deny regex */
#define TX_SVALLOW 0x00000008 /* a server header matches an
allow regex */
#define TX_CLTARPIT 0x00000010 /* the session is tarpitted
(anti-dos) */
+ #define TX_CLDELAY 0x00000020 /* the session is delayed
(anti-dos) */
/* unused: 0x00000020 */
/* transaction flags dedicated to cookies : bits values 0x40, 0x80
(0-3 shift 6) */
diff -c -r ./haproxy-1.3.19/include/types/proxy.h
../haproxy-1.3.19/include/types/proxy.h
*** ./haproxy-1.3.19/include/types/proxy.h Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/include/types/proxy.h Sat Aug 1 22:01:57 2009
- 216,221 ****
--- 216,222 ----
struct { /* WARNING! check
proxy_reset_timeouts() in proxy.h !!! */
int client; /* client I/O timeout
(in ticks) */
int tarpit; /* tarpit timeout,
defaults to connect if unspecified */
+ int delay; /* delay timeout,
defaults to connect if unspecified */
int queue; /* queue timeout,
defaults to connect if unspecified */
int connect; /* connect timeout (in
ticks) */
int server; /* server I/O timeout
(in ticks) */
diff -c -r ./haproxy-1.3.19/src/cfgparse.c ../haproxy-1.3.19/src/cfgparse.c
- ./haproxy-1.3.19/src/cfgparse.c Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/src/cfgparse.c Sat Aug 1 23:36:09 2009
- 887,892 ****
--- 887,893 ----
if (curproxy->cap & PR_CAP_FE) {
curproxy->timeout.client = defproxy.timeout.client;
curproxy->timeout.tarpit = defproxy.timeout.tarpit;
+ curproxy->timeout.delay = defproxy.timeout.delay;
curproxy->timeout.httpreq =
defproxy.timeout.httpreq;
curproxy->uri_auth = defproxy.uri_auth;
curproxy->mon_net = defproxy.mon_net;
- 903,909 ****
curproxy->timeout.server = defproxy.timeout.server;
curproxy->timeout.check = defproxy.timeout.check;
curproxy->timeout.queue = defproxy.timeout.queue;
! curproxy->timeout.tarpit = defproxy.timeout.tarpit;
curproxy->source_addr = defproxy.source_addr;
}
- 904,910 ----
curproxy->timeout.server = defproxy.timeout.server;
curproxy->timeout.check = defproxy.timeout.check;
curproxy->timeout.queue = defproxy.timeout.queue;
! curproxy->timeout.delay = defproxy.timeout.delay;
curproxy->source_addr = defproxy.source_addr;
}
- 3029,3034 ****
--- 3030,3061 ----
chain_regex(&curproxy->req_exp, preg, ACT_ALLOW, NULL);
warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
}
+ else if (!strcmp(args[0], "reqidelay")) { /* delay a request if
a header matches this regex ignoring case */
+ regex_t *preg;
+ if (curproxy == &defproxy) {
+ Alert("parsing [%s:%d] : '%s' not allowed in
'defaults' section.\n", file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ else if (warnifnotcap(curproxy, PR_CAP_RS, file,
linenum, args[0], NULL))
+ err_code |= ERR_WARN;
+
+ if (*(args[1]) == 0) {
+ Alert("parsing [%s:%d] : '%s' expects <regex> as
an argument.\n", file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ preg = calloc(1, sizeof(regex_t));
+ if (regcomp(preg, args[1], REG_EXTENDED | REG_ICASE) != 0) {
+ Alert("parsing [%s:%d] : bad regular expression
'%s'.\n", file, linenum, args[1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ chain_regex(&curproxy->req_exp, preg, ACT_DELAY, NULL);
+ warnif_misplaced_reqxxx(curproxy, file, linenum, args[0]);
+ }
else if (!strcmp(args[0], "reqitarpit")) { /* tarpit a request
if a header matches this regex ignoring case */
regex_t *preg;
if (curproxy == &defproxy) {
- 3811,3816 ****
--- 3838,3853 ----
- parameters have been set or must be copied from
contimeouts.
*/
if (curproxy != &defproxy) {
+ if (!curproxy->timeout.delay ||
+ curproxy->timeout.delay ==
defproxy.timeout.delay) {
+ /* delay timeout not set. We search in
the following order:
+ * default.delay, curr.connect,
default.connect.
+ */
+ if (defproxy.timeout.delay)
+ curproxy->timeout.delay =
defproxy.timeout.delay;
+ else
+ curproxy->timeout.delay = 0;
+ }
if (!curproxy->timeout.tarpit ||
curproxy->timeout.tarpit ==
defproxy.timeout.tarpit) {
/* tarpit timeout not set. We search in
the following order:
diff -c -r ./haproxy-1.3.19/src/proto_http.c
../haproxy-1.3.19/src/proto_http.c
- ./haproxy-1.3.19/src/proto_http.c Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/src/proto_http.c Sun Aug 2 19:00:10 2009
- 2378,2383 ****
--- 2378,2390 ----
if (!req->analyse_exp)
req->analyse_exp = tick_add(now_ms, 0);
}
+ if (txn->flags & TX_CLDELAY) {
+ buffer_write_dis(req);
+ req->analysers |= AN_REQ_HTTP_DELAY;
+ req->analyse_exp = tick_add_ifset(now_ms,
s->be->timeout.delay);
+ if (!req->analyse_exp)
+ req->analyse_exp = tick_add(now_ms, 0);
+ }
/* OK let's go on with the BODY now */
return 1;
- 2443,2449 ****
--- 2450,2502 ----
s->flags |= SN_FINST_T;
return 0;
}
+ int http_process_delay(struct session *s, struct buffer *req)
+ {
+ struct http_txn *txn = &s->txn;
+ if ((req->flags & (BF_SHUTR|BF_READ_ERROR)) == 0 &&
+ !tick_is_expired(req->analyse_exp, now_ms))
+ {
+ buffer_write_dis(req);
+ return 0;
+ }
+ if (req->flags != BF_READ_ERROR)
+ {
+ req->analysers &= ~AN_REQ_HTTP_DELAY;
+ buffer_write_ena(req);
+ return 1;
+ }
+ txn->status = 500;
+ if (req->flags != BF_READ_ERROR)
+ stream_int_retnclose(req->prod, error_message(s,
HTTP_ERR_500));
+ return 0;
+ //req->analysers = 0;
+ //req->analyse_exp = TICK_ETERNITY;
+
+ //s->fe->failed_req++;
+ //if (!(s->flags & SN_ERR_MASK))
+ // s->flags |= SN_ERR_PRXCOND;
+ //if (!(s->flags & SN_FINST_MASK))
+ // s->flags |= SN_FINST_T;
+ //return 0;
+ //if ((req->flags & (BF_READ_ERROR | BF_SHUTR)) == 0)
+ //s->logs.tv_request = now;
+ //req->analysers &= ~AN_REQ_HTTP_DELAY;
+ //txn->flags &= ~TX_CLDELAY;
+ //req->analyse_exp = TICK_ETERNITY;
+ //return 1;
+ //s->logs.tv_request = now;
+ //stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_500));
+ //req->analysers = 0;
+ //req->analyse_exp = TICK_ETERNITY;
+
+ //s->fe->failed_req++;
+ //if (!(s->flags & SN_ERR_MASK))
+ // s->flags |= SN_ERR_PRXCOND;
+ //if (!(s->flags & SN_FINST_MASK))
+ // s->flags |= SN_FINST_R;
+ //return 0;
+ }
/* This function is an analyser which processes the HTTP request body.
It looks
- for parameters to be used for the load balancing algorithm
(url_param). It
- must only be called after the standard HTTP request processing has
occurred,
- 3067,3073 ****
else if (unlikely(txn->flags & TX_CLALLOW) &&
(exp->action == ACT_ALLOW ||
exp->action == ACT_DENY ||
! exp->action == ACT_TARPIT))
return 0;
cur_idx = txn->hdr_idx.v[old_idx].next;
--- 3120,3127 ----
else if (unlikely(txn->flags & TX_CLALLOW) &&
(exp->action == ACT_ALLOW ||
exp->action == ACT_DENY ||
! exp->action == ACT_TARPIT ||
! exp->action == ACT_DELAY))
return 0;
cur_idx = txn->hdr_idx.v[old_idx].next;
- 3133,3138 ****
--- 3187,3197 ----
last_hdr = 1;
t->be->denied_req++;
break;
+ case ACT_DELAY:
+ txn->flags |= TX_CLDELAY;
+ //last_hdr = 1;
+ //t->be->denied_req++;
+ break;
case ACT_REPLACE:
len = exp_replace(trash, cur_ptr,
exp->replace, pmatch);
- 3256,3261 ****
--- 3315,3326 ----
t->be->denied_req++;
done = 1;
break;
+ case ACT_DELAY:
+ txn->flags |= TX_CLDELAY;
+ //t->be->denied_req++;
+ //done = 1;
+ break;
+
case ACT_REPLACE:
*cur_end = term; /* restore the string terminator */
- 3329,3335 ****
*/
apply_filter_to_req_headers(t, req, exp);
}
! exp = exp->next;
}
return 0;
}
--- 3394,3400 ----
*/
apply_filter_to_req_headers(t, req, exp);
}
! exp = exp->next;
}
return 0;
}
diff -c -r ./haproxy-1.3.19/src/proxy.c ../haproxy-1.3.19/src/proxy.c
- ./haproxy-1.3.19/src/proxy.c Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/src/proxy.c Sat Aug 1 21:01:15 2009
- 109,114 ****
--- 109,118 ----
tv = &proxy->timeout.tarpit;
td = &defpx->timeout.tarpit;
cap = PR_CAP_FE | PR_CAP_BE;
+ } else if (!strcmp(args[0], "delay")) {
+ tv = &proxy->timeout.delay;
+ td = &defpx->timeout.delay;
+ cap = PR_CAP_FE | PR_CAP_BE;
} else if (!strcmp(args[0], "http-request")) {
tv = &proxy->timeout.httpreq;
td = &defpx->timeout.httpreq;
- 138,144 ****
} else {
snprintf(err, errlen,
"timeout '%s': must be 'client', 'server',
'connect', 'check', "
! "'appsession', 'queue', 'http-request' or
'tarpit'",
args[0]);
return -1;
}
--- 142,148 ----
} else {
snprintf(err, errlen,
"timeout '%s': must be 'client', 'server',
'connect', 'check', "
! "'appsession', 'queue', 'http-request' ,
'delay' or 'tarpit'",
args[0]);
return -1;
}
diff -c -r ./haproxy-1.3.19/src/session.c ../haproxy-1.3.19/src/session.c
- ./haproxy-1.3.19/src/session.c Mon Jul 27 19:39:21 2009
--- ../haproxy-1.3.19/src/session.c Sat Aug 1 22:43:49 2009
- 751,762 ****
if (!http_process_tarpit(s, s->req))
break;
if (s->req->analysers & AN_REQ_HTTP_BODY)
if
(!http_process_request_body(s, s->req))
break;
/* Just make sure that nobody set a
wrong flag causing an endless loop */
! s->req->analysers &= AN_REQ_INSPECT |
AN_REQ_HTTP_HDR | AN_REQ_HTTP_TARPIT | AN_REQ_HTTP_BODY;
/* we don't want to loop anyway */
break;
--- 751,766 ----
if (!http_process_tarpit(s, s->req))
break;
+ if (s->req->analysers & AN_REQ_HTTP_DELAY)
+ if (!http_process_delay(s, s->req))
+ break;
+
if (s->req->analysers & AN_REQ_HTTP_BODY)
if
(!http_process_request_body(s, s->req))
break;
/* Just make sure that nobody set a
wrong flag causing an endless loop */
! s->req->analysers &= AN_REQ_INSPECT |
AN_REQ_HTTP_HDR | AN_REQ_HTTP_TARPIT | AN_REQ_HTTP_DELAY | AN_REQ_HTTP_BODY;
/* we don't want to loop anyway */
break;
Here's the diff, it's not perfect though (I've been doing it in ee in
Freebsd to test on working system), more like a hack.
Then in config (I do it in the frontend) you should write something like:
timeout delay 30s
reqidelay ^.*Opera.*$
Though this diff skips the delay at all :( dunno why.
Willy Tarreau wrote:
> On Sun, Aug 02, 2009 at 03:29:35PM +0200, Andrew Azarov wrote:
>
>> I've done everything you suggested, now upon the match it gives right
>> away 400 error (passes through the request processing further)... Maybe
>> I should loop inside function to check for the tick? (or maybe shouldn't
>> because it might block?)
>>
>
> your analyser must always check the ticks, yes, as it may be called for
> any reason.
>
>
>> Also is 1.4-dev1 stable enough for production?
>>
>
> yes till now it is (and is used by a few sites who are taking profit of
> its ability to slightly reduce the number of packets per session). It's
> also why I wanted to release it now, before breaking it into pieces due
> to more sensible changes. I'd say that right now it's 1.3.19 + a few
> features. Of course the risk of regression is never 100% null, but it is
> very close right now.
>
>
>> We are kicking ddos bots
>> with haproxy (and very successfully), just that haproxy doesn't have
>> rate limit per ip
>>
>
> planned but not done yet :-/
>
>
>> and delay per request
>>
>
> same :-)
>
>
>> and cookie management
>> (redirecting request, setting and keeping random cookie in memory for 1
>> ip for X time) with bouncing of if cookie is ! .
>>
>
> I had written something on that, with a very complete algorithm which would
> count the number of cookies assigned to clients, as well as the number of
> times a cookie was reused. All that in order to prevent DDoS boxes from
> connecting to your site without analysing your response.
>
>
>> Thought I'd start implementing from the least problematic :) however the
>> arch of this program is complex so I need some time to analyse it, and I
>> don't have that time unfortunately.
>>
>
> Please send me your current patch and config, I can help on this and we'll
> both save some time.
>
> Regards,
> Willy
>
>
>
Best Regards,
Andrew
Received on 2009/08/02 21:16