Re: handling hundreds of reqrep statements

2013-10-23 Thread Patrick Hemmer
 



*From: *Patrick Hemmer hapr...@stormcloud9.net
*Sent: * 2013-10-22 23:32:31 E
*CC: *haproxy@formilux.org
*Subject: *Re: handling hundreds of reqrep statements



 
 *From: *Patrick Hemmer hapr...@stormcloud9.net
 *Sent: * 2013-10-22 19:13:08 E
 *To: *haproxy@formilux.org
 *Subject: *handling hundreds of reqrep statements

 I'm currently using haproxy (1.5-dev19) as a content based router. It
 takes an incoming request, looks at the url, rewrites it, and sends
 it on to the appropriate back end.
 The difficult part is that we need to all parsing and rewriting after
 the first match. This is because we might have a url such as
 '/foo/bar' which rewrites to '/foo/baz', and another rewrite from
 '/foo/b' to '/foo/c'. As you can see both rules would try to trigger
 a rewrite on '/foo/bar/shot', and we'd end up with '/foo/caz/shot'.
 Additionally there are hundreds of these rewrites (the config file is
 generated from a mapping).

 There are 2 questions here:

 1) I currently have this working using stick tables (it's unpleasant
 but it works).
 It basically looks like this:
 frontend frontend1
 acl foo_bar path_reg ^/foo/bar
 use_backend backend1 if foo_bar

 acl foo_b path_reg ^/foo/b
 use_backend backend1 if foo_b

 backend backend1
 stick-table type integer size 1 store gpc0 # create a stick table
 to store one entry
 tcp-request content track-sc1 always_false # enable tracking on
 sc1. The `always_false` doesn't matter, it just requires a key, so we
 give it one
 acl rewrite-init sc1_clr_gpc0 ge 0 # ACL to clear gpc0
 tcp-request content accept if rewrite-init # clear gpc0 on the
 start of every request
 acl rewrite-empty sc1_get_gpc0 eq 0 # ACL to check if gpc0 has
 been set
 acl rewrite-set sc1_inc_gpc0 ge 0 # ACL to set gpc0 when a
 rewrite has matched

 acl foo_bar path_reg ^/foo/bar
 reqrep ^(GET|POST)\ /foo/bar(.*) \1\ /foo/baz\2 if rewrite-empty
 foo_bar rewrite-set # the conditional first checks if another rewrite
 has matched, then checks the foo_bar acl, and then performs the
 rewrite-set only if foo_bar matched

 acl foo_b path_reg ^/foo/b
 reqrep ^(GET|POST)\ /foo/b(.*) \1\ /foo/c\2 if rewrite-empty
 foo_b rewrite-set # same procedure as above

 (my actual rules are a bit more complicated, but those examples
 exhibit all the problem points I have).

 The cleaner way I thought of handling this was to instead do
 something like this:
 backend backend1
 acl rewrite-found req.hdr(X-Rewrite-ID,1) -m found

 acl foo_bar path_reg ^/foo/bar
 reqrep ^(GET|POST)\ /foo/bar(.*) \1\ /foo/baz\2\r\nX-Rewrite-ID:\
 foo_bar if !rewrite-found foo_bar

 acl foo_b path_reg ^/foo/b
 reqrep ^(GET|POST)\ /foo/b(.*) \1\ /foo/c\2\r\nX-Rewrite-ID:\
 foo_b if !rewrite-found foo_b

 But this doesn't work. The rewrite-found acl never finds the header
 and so both reqrep commands run. Is there any better way of doing
 this than the nasty stick table?


 2) I would also like to add a field to the log indicating which rule
 matched. I can't figure out a way to accomplish this bit.
 Since the config file is automatically generated, I was hoping to
 just assign a short numeric ID and stick that in the log somehow. The
 only way I can think that this could work is by adding a header
 conditionally using an acl (or use the header created by the
 alternate idea above), and then using `capture request header` to add
 that to the log. But it does not appear haproxy can capture headers
 added by itself.

 -Patrick

 Ok, so I went home and resumed trying to figure this out, starting
 from scratch on a whole new machine. Well guess what, the cleaner
 way worked. After many proclamations of WTF? out loud (my dog was
 getting concerned), I think I found a bug. And I cannot begin to
 describe just how awesome this bug is.

 Here's how you can duplicate this awesomeness:

 Start a haproxy with the following config:
 defaults
 mode http
 timeout connect 1000
 timeout client 1000
 timeout server 1000

 frontend frontend
 bind *:2082

 maxconn 2

   acl rewrite-found req.hdr(X-Header-ID) -m found

 reqrep ^(GET)\ /foo/(.*) \1\ /foo/\2\r\nX-Header-ID:\ bar if
 !rewrite-found
 reqrep ^(GET)\ /foo/(.*) \1\ /foo/\2\r\nX-Header-ID:\ pop if
 !rewrite-found
 reqrep ^(GET)\ /foo/(.*) \1\ /foo/\2\r\nX-Header-ID:\ tart if
 !rewrite-found

 default_backend backend

 backend backend
 server server 127.0.0.1:2090



 Start up a netcat:
 while true; do nc -l -p 2090; done


 Create a file with the following contents (I'll presume we call it
 data):
 GET /foo/ HTTP/1.1
 Accept: */*
 User-Agent: Agent
 Host: localhost:2082


 (with the empty line on the bottom)

 And now run:
 nc localhost2082  data

 In your listening netcat, notice you got 3 X-Header-ID headers.

 Now in your data file, 

Re: handling hundreds of reqrep statements

2013-10-23 Thread Patrick Hemmer
 



*From: *hushmeh...@hushmail.com
*Sent: * 2013-10-23 01:06:24 E
*To: *hapr...@stormcloud9.net
*CC: *haproxy@formilux.org
*Subject: *Re: handling hundreds of reqrep statements


 On Wed, 23 Oct 2013 05:33:38 +0200 Patrick Hemmer 
 hapr...@stormcloud9.net wrote:
reqrep ^(GET)\ /foo/(.*) \1\ /foo/\2\r\nX-Header-ID:\ bar if
 !rewrite-found
 What about reqadd? Clumsy fiddling with \r\n (or \n\r) in regexp 
 seems awkward to me.
 reqadd X-Header-ID:\ bar unless rewrite-found

Ya, I think I figured out the issue. Had to do with haproxy
pre-allocating buffers for each header, and not expecting them being
moved around.
Unfortunately I can't use reqadd to add a header as reqadd happens too
late in the process. All reqrep statements happen before reqadd. So if I
put an acl on reqrep to skip it if the header has been added, it'll
always run the reqrep because the header gets added afterwards.
However I think I can use http-request set-header instead of reqadd.
It's not as simple as the reqrep \r\n idea, but still better than the
nasty stick table.


Re: Haproxy rate limit per matching request

2013-10-23 Thread Przemysław Hejman
Hi Baptiste,

Thank you for your pieces of advice. I've tried to write such a config, 
however, it does not seem to work - can you tell me what I'm missing or what am 
I doing wrong?

defaults
mode http
contimeout 5000
clitimeout 5
srvtimeout 5


listen app 192.168.9.130:80
mode http
tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst }  
# Just a simple whitelist 
#create a stick table, string type, store number of requests
stick-table type string len 40 size 200k expire 3m
#store url parameter called id
stick store-request urlp(SID,?) # stick on urlp(SID) 
#track counter on url parameter id
tcp-request content track-sc0 urlp(SID,?)
#deny if the number of request for the tracked id is greater than X
tcp-request connection reject if { sc0_http_req_cnt gt 2 }
default_backend web_servers

backend web_servers
balance roundrobin
server web01 192.168.9.128:80 check inter 1000
server web02 192.168.9.129:80 check inter 1000

-- 

e-mail: p...@touk.pl

TouK sp. z o.o. s.k.a.
02-389 Warszawa, al. Bohaterów Września 9
http://touk.pl

Wiadomość napisana przez Baptiste w dniu 18 paź 2013, o godz. 14:40:

 Hi Przemyslaw,
 
 You can do this:
 create a stick table, string type, store number of requests
 store url parameter called id
 track counter on url parameter id
 deny if the number of request for the tracked id is greater than X
 
 Baptiste
 
 
 On Fri, Oct 18, 2013 at 11:02 AM, Przemysław Hejman p...@touk.pl wrote:
 Hello everyone,
 
 
 Is there any possibility for HAProxy to perform a rate limit per repeating
 request? Consider following situation:
 Assume that you have requests like:
 
 GET  /fileid=123%someotherstuff
 GET  /fileid=476%someotherstuff
 GET  /fileid=111%someotherstuff
 GET  /fileid=111%someotherstuff
 GET  /fileid=111%someotherstuff
 GET  /fileid=476%someotherstuff
 
 What I want to do is to block the next request containing id=111.  Lets
 say that I want to allow only 3  exactly same requests matching [0-9]{3}.
 
 Is there any possibility to configure a stick table to work like in this
 example?  If no, do you know any other mechanisms to perform such an action?
 
 Bes
 --
 
 e-mail: p...@touk.pl
 
 TouK sp. z o.o. s.k.a.
 02-389 Warszawa, al. Bohaterów Września 9
 http://touk.pl
 
 



Re: Haproxy rate limit per matching request

2013-10-23 Thread Baptiste
Hi,

Your stick table definition is missing some information.
Use the one below:
stick-table type string len 40 size 200k expire 3m store http_req_cnt

Maybe you should also turn on option http-server-close.

Baptiste


On Wed, Oct 23, 2013 at 7:49 PM, Przemysław Hejman p...@touk.pl wrote:
 Hi Baptiste,

 Thank you for your pieces of advice. I've tried to write such a config,
 however, it does not seem to work - can you tell me what I'm missing or what
 am I doing wrong?

 defaults
 mode http
 contimeout 5000
 clitimeout 5
 srvtimeout 5


 listen app 192.168.9.130:80
 mode http
 tcp-request connection accept if { src -f /etc/haproxy/whitelist.lst
 }  # Just a simple whitelist
 #create a stick table, string type, store number of requests
 stick-table type string len 40 size 200k expire 3m
 #store url parameter called id
 stick store-request urlp(SID,?) # stick on urlp(SID)
 #track counter on url parameter id
 tcp-request content track-sc0 urlp(SID,?)
 #deny if the number of request for the tracked id is greater than X
 tcp-request connection reject if { sc0_http_req_cnt gt 2 }
 default_backend web_servers

 backend web_servers
 balance roundrobin
 server web01 192.168.9.128:80 check inter 1000
 server web02 192.168.9.129:80 check inter 1000

 --

 e-mail: p...@touk.pl

 TouK sp. z o.o. s.k.a.
 02-389 Warszawa, al. Bohaterów Września 9
 http://touk.pl

 Wiadomość napisana przez Baptiste w dniu 18 paź 2013, o godz. 14:40:

 Hi Przemyslaw,

 You can do this:
 create a stick table, string type, store number of requests
 store url parameter called id
 track counter on url parameter id
 deny if the number of request for the tracked id is greater than X

 Baptiste


 On Fri, Oct 18, 2013 at 11:02 AM, Przemysław Hejman p...@touk.pl wrote:

 Hello everyone,



 Is there any possibility for HAProxy to perform a rate limit per repeating

 request? Consider following situation:

 Assume that you have requests like:


 GET  /fileid=123%someotherstuff

 GET  /fileid=476%someotherstuff

 GET  /fileid=111%someotherstuff

 GET  /fileid=111%someotherstuff

 GET  /fileid=111%someotherstuff

 GET  /fileid=476%someotherstuff


 What I want to do is to block the next request containing id=111.  Lets

 say that I want to allow only 3  exactly same requests matching [0-9]{3}.


 Is there any possibility to configure a stick table to work like in this

 example?  If no, do you know any other mechanisms to perform such an action?


 Bes

 --


 e-mail: p...@touk.pl


 TouK sp. z o.o. s.k.a.

 02-389 Warszawa, al. Bohaterów Września 9

 http://touk.pl







Re: haproxy dumps core

2013-10-23 Thread Rainer Duffner

Am 30.07.2013 um 21:40 schrieb Lukas Tribus luky...@hotmail.com:

 Hi Rainer!
 
 
 I'm using haproxy on FreeBSD 9.1-amd64 inside a VMware VM.
 
 I realized that when I have a situation where all servers in a backend
 are down, haproxy crashes:
 Jul 30 08:03:52 px2-bla kernel: pid 58816 (haproxy), uid 80:
 exited on signal 11 (core dumped)
 
 pkg info|grep haproxy
 haproxy-1.4.24 The Reliable, High Performance
 
 can you post the output of haproxy -vv?
 
 
 
 After some tinkering, I got a core-dump out of it:
 
 The core-dump doesn't look very useful, seems like the debugging symbols
 where stripped.
 



Hi,

sorry, I haven't had time to look into this, but now I've been able to generate 
a core (and run it through gdb)


gdb /usr/local/sbin/haproxy haproxy.3272
   
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type show copying to see the conditions.
There is absolutely no warranty for GDB.  Type show warranty for details.
This GDB was configured as amd64-marcel-freebsd...
Core was generated by `haproxy'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libcrypt.so.5...done.
Loaded symbols for /lib/libcrypt.so.5
Reading symbols from /usr/local/lib/libpcreposix.so.0...done.
Loaded symbols for /usr/local/lib/libpcreposix.so.0
Reading symbols from /usr/local/lib/libpcre.so.3...done.
Loaded symbols for /usr/local/lib/libpcre.so.3
Reading symbols from /lib/libc.so.7...done.
Loaded symbols for /lib/libc.so.7
Reading symbols from /lib/libthr.so.3...done.
Loaded symbols for /lib/libthr.so.3
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
#0  0x0043d0e9 in process_session (t=0x801866f00) at src/session.c:1434
1434src/session.c: No such file or directory.
in src/session.c
[New Thread 801807400 (LWP 100105/unknown)]
[New LWP 100114]
(gdb) bt
#0  0x0043d0e9 in process_session (t=0x801866f00) at src/session.c:1434
#1  0x00408420 in process_runnable_tasks (next=0x7fffdafc) at 
src/task.c:234
#2  0x004028e3 in run_poll_loop () at src/haproxy.c:1002
#3  0x0040455d in main (argc=value optimized out, 
argv=0x7fffdba0) at src/haproxy.c:1288


Can you make something of this?


I found it may be a config-file problem.
Apart from comments, the only difference between a config-file that makes 
haproxy dump core and one that doesn't is:

   maxconn 500
   server server1  ip:80 weight 1 check
---
   maxconn 500 server server1  ip:80 weight 1 check



Best Regards
Rainer