Re: HAProxy 1.5-dev7 attempting to connect to real server port of twice virtual server port

2011-09-23 Thread Nick Chalk
Hello Willy.

On 23 September 2011 09:35, Willy Tarreau w...@1wt.eu wrote:
 thanks to your diags and detailed reports, I found the bug and I
 have the fix.

Thanks - that's working for us.

Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: HAProxy 1.5-dev7 attempting to connect to real server port of twice virtual server port

2011-09-22 Thread Nick Chalk
Hello Willy.

On 22 September 2011 22:08, Willy Tarreau w...@1wt.eu wrote:
 Wow, you've hit an amazing bug. I seem to remember we touched that
 area reacently when a server port was ignored. I'll have a look at
 this, because it's very likely that we fixed it wrong.

Thanks. I had another look at it today, but didn't make much progress.

Attempting to work around the problem, I experimented with not setting
the SRV_MAPPORTS flag when there is no port specified in the server
directive - simply commenting-out the else clause on lines 3933-3934
of cfgparse.c. I then added a test for
   ((struct sockaddr_in *)s-req-cons-addr.s.to)-sin_port == 0
in assign_server_address(), and copying the port from
   s-req-prod-addr.c.to
to
   s-req-cons-addr.s.to

Interestingly, this works when HAProxy is run in debug mode, but not
as a daemon. In the latter case, it seems that some of the structure
elements are not set - in particular s-req-prod-addr.c.to.ss_family
and s-req-prod-addr.c.to-sin_port.

I'm not sure if that's expected behaviour when the session structure
doesn't have SRV_MAPPORTS set, but it was certainly confusing!

Thanks for your help.
Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



HAProxy 1.5-dev7 attempting to connect to real server port of twice virtual server port

2011-09-21 Thread Nick Chalk
Afternoon all.

We have come across an interesting problem with HAProxy 1.5-dev7: with
the config below, the proxy attempts to connect to a real server port
of twice the virtual server's port.

listen v1
bind 192.168.69.32:80
mode http
balance leastconn
server backup 127.0.0.1:9081 backup
option httpclose
option redispatch
option abortonclose
maxconn 4
log global
option httplog
server r41 192.168.68.41  weight 1  check port 80  inter 2000  rise 2
 fall 3 minconn 0  maxconn 0

In this example, the client's requests to 192.168.69.32:80 are
forwarded to 192.168.68.41:160.

A bit of digging in the source has led to the assign_server_address()
function in backend.c, in particular the following section:

 if (target_srv(s-target)-state  SRV_MAPPORTS) {
int base_port;

if (!(s-be-options  PR_O_TRANSP) 
!(s-flags  SN_FRT_ADDR_SET))
get_frt_addr(s);

/* First, retrieve the port from the incoming
connection */
base_port = get_host_port(s-req-prod-addr.c.to);

/* Second, assign the outgoing connection's port */
base_port += get_host_port(s-req-prod-addr.s.to);
set_host_port(s-req-cons-addr.s.to, base_port);
}

cfg_parse_listen() appears to set the SRV_MAPPORTS flag, as there is
no destination port specified in the server directive. The proxy
therefore uses the port from s-req-prod-addr.c.to plus
s-req-prod-addr.s.to. With the configuration above, both of these
structure elements have the value 80, resulting in a destination port
of 160.

At that point, I hit a dead end in my understanding of the code. It
would appear that either s-req-prod-addr.c.to or
s-req-prod-addr.s.to are holding the wrong port value, or one of
these structures is being used incorrectly in the sum.

Any pointers for further investigation would be appreciated.

Thanks,
Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: HAProxy 1.5-dev7 attempting to connect to real server port of twice virtual server port

2011-09-21 Thread Nick Chalk
Hello Brane.

On 21 September 2011 21:30, Brane F. Gračnar brane.grac...@najdi.si wrote:
 Try replacing this line with:

 server r41 192.168.68.41:80  weight 1 check inter 2000  rise 2 fall 3 minconn 
 0 maxconn 0

Yes, explicitly specifying the real server port works fine - but
that's exercising a different code path.

Originally, the virtual service was defined with a range of ports, so
the real server had to be specified without a port. I simplified the
configuration for the purposes of testing.

Thanks,
Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: Issues with haproxy 1.5-dev6 2011/04/08 and tproxy Cannot bind to tproxy source address before connect()

2011-04-18 Thread Nick Chalk
On 18 April 2011 14:39, Mark Brooks m...@loadbalancer.org wrote:
 We were having problems using transparent proxy and haproxy and
 1.5-dev6 2011/04/08, where haproxy would not work with tproxy enabled.
...
 We were able to get it working in 1.5-dev6 by reversing the change
 made from dev5 to dev6 below is the patch -

 --- proto_tcp.c-dev6    2011-04-18 14:05:38.0 +0100
 +++ proto_tcp.c 2011-04-18 14:12:31.0 +0100
 @@ -150,7 +150,7 @@

        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) one, sizeof(one));
        if (foreign_ok) {
 -               ret = bind(fd, (struct sockaddr *)bind_addr, 
 get_addr_len(bind_addr));
 +               ret = bind(fd, (struct sockaddr *)bind_addr, 
 sizeof(bind_addr));
                if (ret  0)
                        return 2;
        }

It appears that bind_addr.ss_family is not being set in
tcp_bind_socket() before the call to get_addr_len(bind_addr).

The following allows the use of get_addr_len():


--- proto_tcp.c-dev62011-04-18 14:05:38.0 +0100
+++ proto_tcp.c 2011-04-18 15:23:41.0 +0100
@@ -138,12 +138,14 @@
((struct sockaddr_in
*)bind_addr)-sin_addr = ((struct sockaddr_in *)remote)-sin_addr;
if (flags  2)
((struct sockaddr_in
*)bind_addr)-sin_port = ((struct sockaddr_in *)remote)-sin_port;
+   bind_addr.ss_family = AF_INET;
break;
case AF_INET6:
if (flags  1)
((struct sockaddr_in6
*)bind_addr)-sin6_addr = ((struct sockaddr_in6 *)remote)-sin6_addr;
if (flags  2)
((struct sockaddr_in6
*)bind_addr)-sin6_port = ((struct sockaddr_in6 *)remote)-sin6_port;
+   bind_addr.ss_family = AF_INET6;
break;
}
}


Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: httpchk - checking request body

2010-03-13 Thread Nick Chalk
Hello Anze.

On 13 March 2010 10:28, Anze anzen...@volja.net wrote:
 Here is my config:
...
 listen  webfarm 123.123.123.123:80
        mode http
        stats enable
        balance roundrobin
        stats auth user:pass
        cookie SERVERID insert indirect
        option httpclose
        option forwardfor except 123.123.123.123
        # option httpchk HEAD /check.php HTTP/1.0
        # option httpchk /check.php
        # http-check expect string all_is_ok
        server a0 10.0.0.1:8080 cookie a0 check
        server a1 10.0.0.2:8080 cookie a1 check
 -

 I have played with the 3 uncommented lines in listen section - these are the
 results:
...
 With 1.4.1 WITH patch applied:
 - all 3 lines disabled: system works (serves content, no problem, but no
 check)
 - only 1. line enabled: ERROR, haproxy tells all hosts are down (when they are
 not)
 - only 2. line enabled: ERROR, haproxy tells all hosts are down (when they are
 not)
 - 2. and 3. line or 1. and 3. line enabled: ERROR as above.

On the ToDo list is better logging of what httpchk is doing - along
with working out all the options to the original patch.

As a quick test, try adding the following options in place of the
commented-out lines above:

   option httpchk GET /check.php HTTP/1.0
   http-check expect rstring all_is_ok

The 'string' test should work, but it's had less testing than
'rstring'. I've not tried the HEAD method; I can't see it working with
'expect'.

Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: httpchk - checking request body

2010-03-13 Thread Nick Chalk
Hello Anze.

On 13 March 2010 20:08, Anze anzen...@volja.net wrote:
 Interesting. Have you run haproxy -d from the command line to check
 the debugging output? option log-health-checks is also useful.
 I was running it from the command line (too) because logging was not working
 (rsyslogd's UDP support was disabled). That was the output I have sent in the
 first mails.

Ah, missed that email.

 It's a half-close. HAProxy only sends one request, and then waits for
 the response, so we might as well close the transmit channel.
 Are you sure nothing is being sent anymore through this socket? Never?

Not in my packet traces. HAProxy sends one request, receives the
response from the real server, real server closes its channel, HAProxy
replies with RST. Future tests bind a new socket.

 When tcpdump'ing the problem system that led me to work on this, I
 found that HAProxy was not closing the transmit channel properly. The
 real servers were sending FIN to close their side, and HAProxy was
 responding with RST. So I put in the half-close to make sure the
 connection was cleanly shut down.
 I think this is not the proper way to deal with this, but as I said, I am no
 expert in sockets programming.

Neither am I - my background is in System/Network Admin. I'm also just
learning the HAProxy code, so there may be a better way to ensure that
the check connection is closed properly.

 I would say that haproxy still tries to sent RST but can't - which leads to an
 error somewhere.

The RST should not be sent - that's a response to an already-closed
socket. However, HAProxy is not signalling that the connection should
be closed by sending a FIN.

 It's interesting that this has caused problems in your system. As well
 as running HAProxy in debug mode, would you be able to do a tcpdump on
 the system running haproxy? If you could do that both with and without
 the half-close, that would be very useful.
 Hmmm, I am a bit out of depths here. I would love to help out, but please send
 me more specific instructions on what you need.

 What arguments should I use with tcpdump so it helps you? Also, if you don't
 mind, I'd like to send it privately to you and Willy (so I don't need to clean
 up too much private / security sensitive info from it).

I have no problem with you sending it to me directly.

My usual tcpdump invocation is:
   tcpdump -i any -s 0 -w output_file
Substitute an appropriate filename for output_file. You won't want
to leave this running for too long, as it listens on all interfaces
and captures the whole of every packet. I'd suggest starting the
tcpdump, then start HAProxy, wait for a few health checks to be sent,
then stop the tcpdump with Ctrl-C.

 If required, I can send you a version of checks.c with debugging code
 in it - that will dump a lot of data on the checks if you run it in
 debug.
 Sure, bring it on. ;)

I'll send that directly to you, rather than the list...

 Those two will not check the content - I'll need to trawl through the
 config code to check whether it defaults to checking the HTTP return
 code in these cases.
 I have tested GET with the fixed version (no half-closed socket) and it works.

Interesting. I'll test that locally.

Thanks for your help debugging this.

Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: Truncated health check response from real servers

2010-03-11 Thread Nick Chalk
Hello Willy.

On 8 March 2010 21:25, Willy Tarreau w...@1wt.eu wrote:
 On Mon, Mar 08, 2010 at 04:32:54PM +, Nick Chalk wrote:
 Attached is a patch against v1.4.1. It contains the updated ECV patch,
 and the hacks to work around check responses that span multiple
 packets.
 At first glance, it seems fine. I'll have to find my notes about the
 original patch to see if anything I spot back then is still present,
 but in my opinion it looks OK.

Thanks.

 I don't remember if there were any doc in the original patch either, I'll have
 to dig.

No, I don't think we have any documentation. I'll try to find some
time to add that to the patch.

Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: Truncated health check response from real servers

2010-03-08 Thread Nick Chalk
Hello Willy.

On 3 March 2010 20:31, Willy Tarreau w...@1wt.eu wrote:
 OK that's perfect then. If you don't manage to sort out your issue
 with small packets, do not hesitate to post your work in progress
 to the list, it often helps a lot to work iteratively.

The small-packet problem turned out to be a testing fault - the apache
servers I'm using for testing were not sending the whole page when I
had set a small MTU.

Attached is a patch against v1.4.1. It contains the updated ECV patch,
and the hacks to work around check responses that span multiple
packets.

It seems to be working fine in my tests, and handles check responses
that are bigger than the buffer.

I'd be grateful for anyone's comments and suggestions.

Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/
diff -ur haproxy-1.4.1/include/types/proxy.h haproxy-1.4.1-ecv/include/types/proxy.h
--- haproxy-1.4.1/include/types/proxy.h	2010-03-04 22:39:19.0 +
+++ haproxy-1.4.1-ecv/include/types/proxy.h	2010-03-08 10:38:22.0 +
@@ -137,6 +137,8 @@
 #define PR_O2_MYSQL_CHK 0x0002  /* use MYSQL check for server health */
 #define PR_O2_USE_PXHDR 0x0004  /* use Proxy-Connection for proxy requests */
 #define PR_O2_CHK_SNDST 0x0008  /* send the state of each server along with HTTP health checks */
+#define PR_O2_EXPECT	0x0010	/* http-check expect sth */
+#define PR_O2_NOEXPECT	0x0020	/* http-check expect ! sth */
 /* end of proxy-options2 */
 
 /* bits for sticking rules */
@@ -274,6 +276,9 @@
 	int grace;/* grace time after stop request */
 	char *check_req;			/* HTTP or SSL request to use for PR_O_HTTP_CHK|PR_O_SSL3_CHK */
 	int check_len;/* Length of the HTTP or SSL3 request */
+	char *expect_str;			/* http-check expected content */
+	regex_t *expect_regex;			/* http-check expected content */
+	char *expect_type;			/* type of http-check, such as status, string */
 	struct chunk errmsg[HTTP_ERR_SIZE];	/* default or customized error messages for known errors */
 	int uuid;/* universally unique proxy ID, used for SNMP */
 	unsigned int backlog;			/* force the frontend's listen backlog */
diff -ur haproxy-1.4.1/include/types/server.h haproxy-1.4.1-ecv/include/types/server.h
--- haproxy-1.4.1/include/types/server.h	2010-03-04 22:39:19.0 +
+++ haproxy-1.4.1-ecv/include/types/server.h	2010-03-08 10:38:22.0 +
@@ -147,6 +147,9 @@
 	struct freq_ctr sess_per_sec;		/* sessions per second on this server */
 	int puid;/* proxy-unique server ID, used for SNMP */
 
+	char *check_data;			/* storage of partial check results */
+	int check_data_len;			/* length of partial check results stored in check_data */
+
 	struct {
 		const char *file;		/* file where the section appears */
 		int line;			/* line where the section appears */
diff -ur haproxy-1.4.1/src/cfgparse.c haproxy-1.4.1-ecv/src/cfgparse.c
--- haproxy-1.4.1/src/cfgparse.c	2010-03-04 22:39:19.0 +
+++ haproxy-1.4.1-ecv/src/cfgparse.c	2010-03-08 10:38:22.0 +
@@ -2874,8 +2874,65 @@
 			/* enable emission of the apparent state of a server in HTTP checks */
 			curproxy-options2 |= PR_O2_CHK_SNDST;
 		}
+		else if (strcmp(args[1], expect) == 0) {
+			if (strcmp(args[2], status) == 0 || strcmp(args[2], string) == 0) {
+curproxy-options2 |= PR_O2_EXPECT;
+if (*(args[3]) == 0) {
+	Alert(parsing [%s:%d] : '%s %s %s' expects  regex as an argument.\n, 
+		file, linenum, args[0], args[1], args[2]);
+	return -1;
+}
+curproxy-expect_type = strdup(args[2]);
+curproxy-expect_str = strdup(args[3]);
+			}
+else if (strcmp(args[2], rstatus) == 0 || strcmp(args[2], rstring) == 0) {
+curproxy-options2 |= PR_O2_EXPECT;
+if (*(args[3]) == 0) {
+Alert(parsing [%s:%d] : '%s %s %s' expects  regex as an argument.\n,
+file, linenum, args[0], args[1], args[2]);
+return -1;
+}
+curproxy-expect_regex = calloc(1, sizeof(regex_t));
+if (regcomp(curproxy-expect_regex, args[3], REG_EXTENDED) != 0) {
+Alert(parsing [%s:%d] : bad regular expression '%s'.\n, file, linenum, args[0]);
+return -1;
+}
+curproxy-expect_type = strdup(args[2]);
+}
+else if (strcmp(args[2], !) == 0 ) {
+curproxy-options2 |= PR_O2_NOEXPECT;
+if (strcmp(args[3], status) == 0 || strcmp(args[3], string) == 0) {
+	if (*(args[4]) == 0) {
+	Alert(parsing [%s:%d] : '%s %s %s %s' expects  regex as an argument

Re: Truncated health check response from real servers

2010-03-03 Thread Nick Chalk
Hello Willy.

On 2 March 2010 21:45, Willy Tarreau w...@1wt.eu wrote:
 If your quick ack already works for one single check, then simply
 allocate a buffer for each server in cfgparse.c, and have the
 checks functions use that server-specific buffer instead of
 trash.

Thanks for the pointer. I've added buffer and length variables to
struct server, and allocated space with the rest of the server
initialisation. Looks to be stable so far, although there's still a
problem with very small response packets - something I'll work on
tomorrow.

 If you come up with something working well, I'm willing to merge
 it into 1.4, so please do not hesitate to submit your work in
 progress. You'll also get more testers.

When I have something working and presentable, I'll submit the patch.

Thanks,
Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: Truncated health check response from real servers

2010-03-02 Thread Nick Chalk
Hello Willy.

On 25 February 2010 20:25, Willy Tarreau w...@1wt.eu wrote:
 On Mon, Feb 15, 2010 at 10:05:57AM +, Nick Chalk wrote:
 On 13 February 2010 10:40, Willy Tarreau w...@1wt.eu wrote:
  Indeed, with MSG_PEEK we have no way to tell the connection was closed.

 For the time being, I've hacked together a patch to get our customer
 up and running.

 I've allocated a new static character buffer, to store the
 intermediate results from the real server. I'm relying on recv()
 returning a length of 0 to indicate the server has closed the
 connection - not sure if that's a reliable method, but it seems to be
 repeatable.

 It will not always work with MSG_PEEK.

Sorry, I should have made it clear that I'd removed the MSG_PEEK flag.

 The other temporary solution will be to allocate a receive buffer to
 every server to store health check responses.

Hmm, I hadn't considered that multiple checks could be running in
parallel. I'll have a look at whether that can break my quick hack.

Thanks,
Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/



Re: Truncated health check response from real servers

2010-02-15 Thread Nick Chalk
Hello Willy, Krzysztof.

On 13 February 2010 10:40, Willy Tarreau w...@1wt.eu wrote:
 On Fri, Feb 12, 2010 at 05:47:41PM +0100, Krzysztof Olędzki wrote:
 There are several issues with the fix:

  - we need to check if connection is not closed, as it is pointless to
 use MSG_PEEK and restarting such check if there is no more data we are
 able to read

 Indeed, with MSG_PEEK we have no way to tell the connection was closed.

For the time being, I've hacked together a patch to get our customer
up and running.

I've allocated a new static character buffer, to store the
intermediate results from the real server. I'm relying on recv()
returning a length of 0 to indicate the server has closed the
connection - not sure if that's a reliable method, but it seems to be
repeatable.

  - some servers return empty description so increasing minimum response
 length prevents haproxy from accepting such checks. Of course, if you
 are not using such server, it should be safe to do it in your locally
 patched version, but we mustn't do it on a public version.

 In fact, we should re-parse the response each time we call recv(). As
 long as we don't find a complete response, we can wait. This still
 implies a non-trivial change to current code.

I decided not to run the content check for every received packet, as I
couldn't see an easy way to deal with the case where the string to
match is split between two packets.

Nick.

-- 
Nick Chalk.

Loadbalancer.org Ltd.
Phone: +44 (0)870 443 8779
http://www.loadbalancer.org/