Backend connection issues with FIPS

2024-06-06 Thread Lowin, Patrick
Dear HAProxy friends,

we were debugging an issue in one of our staging systems on a FIPS compliant 
version of Ubuntu Jammy (22.04.4): 
https://github.com/haproxy/haproxy/issues/2588.

At this point, we tried various actions without understanding the root cause 
like turning off non-haproxy-processes or changing TLS versions and ran out of 
ideas. If someone observed similar behavior in the past and could share some 
insights or has ideas how to debug this, please join us on the issue linked 
above!

Thanks a lot and best regards,
Patrick


Wildcards vs concrete SNIs in crt-list

2023-12-08 Thread Lowin, Patrick
Dear community,

we are using the crt-list for different mTLS configs with the same certificate. 
I’d like to align on some details combining wildcard and tenant-specific SNIs.

>From current experiments with 2.7.10, the order of the crt-list seems not to 
>matter but the best-fitting SNI is chosen:
# crt-list:
/my-domain.pem [verify none] *.my.domain
/my-domain.pem [verify optional ca-file /some-ca.pem] test123.my.domain
# connection to abc.my.domain offers no CAs as expected
# connection to test123.my.domain offers the CA as desired

IIRC, this was different in the past, the wildcard entry was used and also no 
CAs were offered for test123.

Does somebody have more implementation details on this? Can I rely on my 
observations for all crt-list properties, like ciphers and others?

Best regards,
Patrick


Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2020-05-07 Thread Patrick Gansterer
On 07.05.20 18:23, Tim Düsterhus wrote:> This is about your "[PATCH 1/2] 
MINOR: crypto: Move aes_gcm_dec

implementation into new file". It does not contain a body, but instead
just a subject.


Ok, agree.


I skipped the patch (that's why I did not ACK the first, but only the
second one), because it was a very large change of code that was just
moved. Nonetheless I should have noticed the missing body and noted that
during my review.


IMHO, that's a patch you usually do not want review.


Please note that I review patches on a voluntary basis. I'm not an
"employed first level reviewer".


That's not what I meant. I thought that when regular participants on 
this list do not spot the errors of first time contributes, it can't be 
that obvious and directing to CONTRIBUTING might not be enough.



Liking HAProxy and wanting to give something back is my motivation as
well. I am very sorry to see how this experience went for you. If it is
of any help to you: This is definitely not how it usually goes.


Then here is my next try. ;-)

I've rebased my changes to reflect the recent changes and added the 
missing description to the first patch.


- Patrick
>From 9125c6df81e135275c450a0be32bcd0b58ef2099 Mon Sep 17 00:00:00 2001
From: Patrick Gansterer 
Date: Sun, 17 Jun 2018 11:21:11 +0200
Subject: [PATCH 1/2] MINOR: crypto: Move aes_gcm_dec implementation into new
 file

aes_gcm_dec is independent of the TLS implementation and fits better
in a separate file dedicated to crypto functionality.
This gives converters which depend on OpenSSL a clear home.
---
 Makefile   |   2 +-
 src/crypto.c   | 163 +
 src/ssl_sock.c | 142 --
 3 files changed, 164 insertions(+), 143 deletions(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 1e4213989..2dea46368 100644
--- a/Makefile
+++ b/Makefile
@@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index 0..74b92eee5
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,163 @@
+/*
+ * Crypto converters
+ *
+ * Copyright 2020 Nenad Merdanovic 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000100fL)
+static inline int sample_conv_var2smp_str(const struct arg *arg, struct sample *smp)
+{
+	switch (arg->type) {
+	case ARGT_STR:
+		smp->data.type = SMP_T_STR;
+		smp->data.u.str = arg->data.str;
+		return 1;
+	case ARGT_VAR:
+		if (!vars_get_by_desc(>data.var, smp))
+return 0;
+		if (!sample_casts[smp->data.type][SMP_T_STR])
+return 0;
+		if (!sample_casts[smp->data.type][SMP_T_STR](smp))
+return 0;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
+		  const char *file, int line, char **err)
+{
+	switch(args[0].data.sint) {
+	case 128:
+	case 192:
+	case 256:
+		break;
+	default:
+		memprintf(err, "key size must be 128, 192 or 256 (bits).");
+		return 0;
+	}
+	/* Try to decode a variable. */
+	vars_check_arg([1], NULL);
+	vars_check_arg([2], NULL);
+	vars_check_arg([3], NULL);
+	return 1;
+}
+
+/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
+static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
+{
+	struct sample nonce, key, aead_tag;
+	struct buffer *smp_trash, *smp_trash_alloc;
+	EVP_CIPHER_CTX *ctx;
+	int dec_size, ret;
+
+	smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[1], ))
+		return 0;
+
+	smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[2], ))
+		return 0;
+
+	smp_set_owner(_tag, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[3], _tag))
+		return 0;
+
+	smp_trash = get_trash_chunk();
+	smp_trash_alloc = alloc_trash_chunk();
+	if (!smp_trash_alloc)
+		return 0;
+
+	ctx = EVP_CIPHER_CTX_new();
+
+	if (!ctx)
+		goto err;
+
+	dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
+	if (dec_size < 0)
+		goto err;
+	smp_trash->data = dec_size;
+
+	/* Set cipher type and mode */
+	switch(arg_p[0].data.sint) {
+	case 128:
+		EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);

Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2020-05-07 Thread Patrick Gansterer

On 07.05.20 17:35, Willy Tarreau wrote:

Indeed. I encourage to ping again after one week because usually when you
restart with a new week of work, the previous one is definitely in old
history and will only be revisited by pure luck.


I don't want to look impatient, so I waited 2 weeks. ;-)


With this said, I remember having noticed Tim's ack and was about to take
the series until I noticed there was a first patch with no commit message
to justify the change and postponed the reply because I had other things
to do than to rehash what's already in CONTRIBUTING again and again :-/


I'm not sure how I should read this. I wrote an explanation into the 
commit message and tried to match already existing messages. If I look 
at commits in the last days like 0e9d87bf06 or de80201460 there are no 
very long commit messages either.


If I should write an essay about my use case into the commit message I 
could do that, but that's something a "first level reviewer" could 
demand already.


I read the CONTRIBUTING text before submitting my patch, since I don't 
like to repeat myself also, but it's hard to get everything right in the 
first patch. Sorry for that.


I really like haproxy and want to give something back, but I'm not sure 
if I want to do that in the future with the experience I had so far. :-(


- Patrick



Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2020-04-22 Thread Patrick Gansterer
Tim,

thx for the quick review. I attached a new patchset.

On Mittwoch, 22. April 2020 18:01:01 CEST Tim Düsterhus wrote:
> Small nit: It should read 'e.g.' (with a dot at the end).

Argh. Can't believe how many typos I made in this lines. ^^

> I believe you support a variable key now. You should add this to the doc
> (and the reg-test) then.

Done.

- Patrick>From 8f6ce045c80e0f67a485233ee602b57b4c311bde Mon Sep 17 00:00:00 2001
From: Patrick Gansterer 
Date: Sun, 17 Jun 2018 11:21:11 +0200
Subject: [PATCH 1/2] MINOR: crypto: Move aes_gcm_dec implementation into new
 file

---
 Makefile   |   2 +-
 src/crypto.c   | 163 +
 src/ssl_sock.c | 142 --
 3 files changed, 164 insertions(+), 143 deletions(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 1e4213989..2dea46368 100644
--- a/Makefile
+++ b/Makefile
@@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index 0..74b92eee5
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,163 @@
+/*
+ * Crypto converters
+ *
+ * Copyright 2020 Nenad Merdanovic 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000100fL)
+static inline int sample_conv_var2smp_str(const struct arg *arg, struct sample *smp)
+{
+	switch (arg->type) {
+	case ARGT_STR:
+		smp->data.type = SMP_T_STR;
+		smp->data.u.str = arg->data.str;
+		return 1;
+	case ARGT_VAR:
+		if (!vars_get_by_desc(>data.var, smp))
+return 0;
+		if (!sample_casts[smp->data.type][SMP_T_STR])
+return 0;
+		if (!sample_casts[smp->data.type][SMP_T_STR](smp))
+return 0;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
+		  const char *file, int line, char **err)
+{
+	switch(args[0].data.sint) {
+	case 128:
+	case 192:
+	case 256:
+		break;
+	default:
+		memprintf(err, "key size must be 128, 192 or 256 (bits).");
+		return 0;
+	}
+	/* Try to decode a variable. */
+	vars_check_arg([1], NULL);
+	vars_check_arg([2], NULL);
+	vars_check_arg([3], NULL);
+	return 1;
+}
+
+/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
+static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
+{
+	struct sample nonce, key, aead_tag;
+	struct buffer *smp_trash, *smp_trash_alloc;
+	EVP_CIPHER_CTX *ctx;
+	int dec_size, ret;
+
+	smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[1], ))
+		return 0;
+
+	smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[2], ))
+		return 0;
+
+	smp_set_owner(_tag, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[3], _tag))
+		return 0;
+
+	smp_trash = get_trash_chunk();
+	smp_trash_alloc = alloc_trash_chunk();
+	if (!smp_trash_alloc)
+		return 0;
+
+	ctx = EVP_CIPHER_CTX_new();
+
+	if (!ctx)
+		goto err;
+
+	dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
+	if (dec_size < 0)
+		goto err;
+	smp_trash->data = dec_size;
+
+	/* Set cipher type and mode */
+	switch(arg_p[0].data.sint) {
+	case 128:
+		EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
+		break;
+	case 192:
+		EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
+		break;
+	case 256:
+		EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
+		break;
+	}
+
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, smp_trash->data, NULL);
+
+	/* Initialise IV */
+	if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) smp_trash->area))
+		goto err;
+
+	dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
+	if (dec_size < 0)
+		goto err;
+	smp_trash->data = dec_size;
+
+	/* Initialise key */
+	if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) smp_trash->area, NULL))
+		goto err;
+
+	if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) _trash->data,
+		  (unsigned char *) smp->data.u.str.area, (int) smp->data.u.str.data))
+		goto err;
+
+	dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->

Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2020-04-22 Thread Patrick Gansterer
Tim,

sorry for the troubles. My mail program added automatic line breaks. :-(

I attached the two files now.

- Patrick
>From 8f6ce045c80e0f67a485233ee602b57b4c311bde Mon Sep 17 00:00:00 2001
From: Patrick Gansterer 
Date: Sun, 17 Jun 2018 11:21:11 +0200
Subject: [PATCH 1/2] MINOR: crypto: Move aes_gcm_dec implementation into new
 file

---
 Makefile   |   2 +-
 src/crypto.c   | 163 +
 src/ssl_sock.c | 142 --
 3 files changed, 164 insertions(+), 143 deletions(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 1e4213989..2dea46368 100644
--- a/Makefile
+++ b/Makefile
@@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index 0..74b92eee5
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,163 @@
+/*
+ * Crypto converters
+ *
+ * Copyright 2020 Nenad Merdanovic 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000100fL)
+static inline int sample_conv_var2smp_str(const struct arg *arg, struct sample *smp)
+{
+	switch (arg->type) {
+	case ARGT_STR:
+		smp->data.type = SMP_T_STR;
+		smp->data.u.str = arg->data.str;
+		return 1;
+	case ARGT_VAR:
+		if (!vars_get_by_desc(>data.var, smp))
+return 0;
+		if (!sample_casts[smp->data.type][SMP_T_STR])
+return 0;
+		if (!sample_casts[smp->data.type][SMP_T_STR](smp))
+return 0;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
+		  const char *file, int line, char **err)
+{
+	switch(args[0].data.sint) {
+	case 128:
+	case 192:
+	case 256:
+		break;
+	default:
+		memprintf(err, "key size must be 128, 192 or 256 (bits).");
+		return 0;
+	}
+	/* Try to decode a variable. */
+	vars_check_arg([1], NULL);
+	vars_check_arg([2], NULL);
+	vars_check_arg([3], NULL);
+	return 1;
+}
+
+/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are base64 encoded */
+static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample *smp, void *private)
+{
+	struct sample nonce, key, aead_tag;
+	struct buffer *smp_trash, *smp_trash_alloc;
+	EVP_CIPHER_CTX *ctx;
+	int dec_size, ret;
+
+	smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[1], ))
+		return 0;
+
+	smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[2], ))
+		return 0;
+
+	smp_set_owner(_tag, smp->px, smp->sess, smp->strm, smp->opt);
+	if (!sample_conv_var2smp_str(_p[3], _tag))
+		return 0;
+
+	smp_trash = get_trash_chunk();
+	smp_trash_alloc = alloc_trash_chunk();
+	if (!smp_trash_alloc)
+		return 0;
+
+	ctx = EVP_CIPHER_CTX_new();
+
+	if (!ctx)
+		goto err;
+
+	dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, smp_trash->area, smp_trash->size);
+	if (dec_size < 0)
+		goto err;
+	smp_trash->data = dec_size;
+
+	/* Set cipher type and mode */
+	switch(arg_p[0].data.sint) {
+	case 128:
+		EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL);
+		break;
+	case 192:
+		EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, NULL);
+		break;
+	case 256:
+		EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
+		break;
+	}
+
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, smp_trash->data, NULL);
+
+	/* Initialise IV */
+	if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) smp_trash->area))
+		goto err;
+
+	dec_size = base64dec(key.data.u.str.area, key.data.u.str.data, smp_trash->area, smp_trash->size);
+	if (dec_size < 0)
+		goto err;
+	smp_trash->data = dec_size;
+
+	/* Initialise key */
+	if (!EVP_DecryptInit_ex(ctx, NULL, NULL, (unsigned char *) smp_trash->area, NULL))
+		goto err;
+
+	if (!EVP_DecryptUpdate(ctx, (unsigned char *) smp_trash->area, (int *) _trash->data,
+		  (unsigned char *) smp->data.u.str.area, (int) smp->data.u.str.data))
+		goto err;
+
+	dec_size = base64dec(aead_tag.data.u.str.area, aead_tag.data.u.str.data, smp_trash_alloc->area, smp_trash_alloc->size);
+	if (dec_size < 0)
+		goto err;
+	smp_trash_alloc->data = dec_size;
+	dec_size = smp_trash->data;
+
+	EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, smp_trash_alloc->data, (void *) smp_trash_alloc->area);
+	ret = EVP_DecryptFinal_

Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2020-04-22 Thread Patrick Gansterer
Tim,

thanks for the review. I just rebased my old patch today and didn't check what 
changed in the meantime in the codebase. I created a separate patch to move 
aes_gcm_dec out of ssl_sock.c since it seams to fit better to my new file.

- Patrick

>From 8f6ce045c80e0f67a485233ee602b57b4c311bde Mon Sep 17 00:00:00 2001
From: Patrick Gansterer 
Date: Sun, 17 Jun 2018 11:21:11 +0200
Subject: [PATCH 1/2] MINOR: crypto: Move aes_gcm_dec implementation into new
 file

---
 Makefile   |   2 +-
 src/crypto.c   | 163 +
 src/ssl_sock.c | 142 --
 3 files changed, 164 insertions(+), 143 deletions(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 1e4213989..2dea46368 100644
--- a/Makefile
+++ b/Makefile
@@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl -
lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index 0..74b92eee5
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,163 @@
+/*
+ * Crypto converters
+ *
+ * Copyright 2020 Nenad Merdanovic 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000100fL)
+static inline int sample_conv_var2smp_str(const struct arg *arg, struct 
sample *smp)
+{
+   switch (arg->type) {
+   case ARGT_STR:
+   smp->data.type = SMP_T_STR;
+   smp->data.u.str = arg->data.str;
+   return 1;
+   case ARGT_VAR:
+   if (!vars_get_by_desc(>data.var, smp))
+   return 0;
+   if (!sample_casts[smp->data.type][SMP_T_STR])
+   return 0;
+   if (!sample_casts[smp->data.type][SMP_T_STR](smp))
+   return 0;
+   return 1;
+   default:
+   return 0;
+   }
+}
+
+static int check_aes_gcm(struct arg *args, struct sample_conv *conv,
+ const char 
*file, int line, char **err)
+{
+   switch(args[0].data.sint) {
+   case 128:
+   case 192:
+   case 256:
+   break;
+   default:
+   memprintf(err, "key size must be 128, 192 or 256 
(bits).");
+   return 0;
+   }
+   /* Try to decode a variable. */
+   vars_check_arg([1], NULL);
+   vars_check_arg([2], NULL);
+   vars_check_arg([3], NULL);
+   return 1;
+}
+
+/* Arguments: AES size in bits, nonce, key, tag. The last three arguments are 
base64 encoded */
+static int sample_conv_aes_gcm_dec(const struct arg *arg_p, struct sample 
*smp, void *private)
+{
+   struct sample nonce, key, aead_tag;
+   struct buffer *smp_trash, *smp_trash_alloc;
+   EVP_CIPHER_CTX *ctx;
+   int dec_size, ret;
+
+   smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+   if (!sample_conv_var2smp_str(_p[1], ))
+   return 0;
+
+   smp_set_owner(, smp->px, smp->sess, smp->strm, smp->opt);
+   if (!sample_conv_var2smp_str(_p[2], ))
+   return 0;
+
+   smp_set_owner(_tag, smp->px, smp->sess, smp->strm, smp->opt);
+   if (!sample_conv_var2smp_str(_p[3], _tag))
+   return 0;
+
+   smp_trash = get_trash_chunk();
+   smp_trash_alloc = alloc_trash_chunk();
+   if (!smp_trash_alloc)
+   return 0;
+
+   ctx = EVP_CIPHER_CTX_new();
+
+   if (!ctx)
+   goto err;
+
+   dec_size = base64dec(nonce.data.u.str.area, nonce.data.u.str.data, 
smp_trash->area, smp_trash->size);
+   if (dec_size < 0)
+   goto err;
+   smp_trash->data = dec_size;
+
+   /* Set cipher type and mode */
+   switch(arg_p[0].data.sint) {
+   case 128:
+   EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, 
NULL);
+   break;
+   case 192:
+   EVP_DecryptInit_ex(ctx, EVP_aes_192_gcm(), NULL, NULL, 
NULL);
+   break;
+   case 256:
+   EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, 
NULL);
+   break;
+   }
+
+   EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, smp_trash->data, 
NULL);
+
+   /* Initialise IV */
+   if(!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, (unsigned char *) 
smp_trash->area))
+   goto err;
+
+   dec_size = base64dec(key.data.u.

[PATCH] MINOR: crypto: Add digest and hmac converters

2020-04-22 Thread Patrick Gansterer
Make the digest and HMAC function of OpenSSL accessible to the user via
converters. They can be used to sign and validate content.
---
 Makefile|  2 +-
 doc/configuration.txt   |  9 
 reg-tests/sample_fetches/hashes.vtc | 22 
 src/crypto.c| 84 +
 4 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 1e4213989..2dea46368 100644
--- a/Makefile
+++ b/Makefile
@@ -542,7 +542,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl 
-lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 2e548b66c..17b2debe5 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13918,6 +13918,10 @@ debug([])
   Example:
 tcp-request connection track-sc0 src,debug(track-sc)
 
+digest()
+  Converts a binary input sample to a message digest. The result is a binary
+  sample. The algorithm must be an OpenSSL message digest name (e.g sha256).
+
 div()
   Divides the input value of type signed integer by , and returns the
   result as an signed integer. If  is null, the largest unsigned
@@ -13972,6 +13976,11 @@ hex2i
   Converts a hex string containing two hex digits per input byte to an
   integer. If the input value cannot be converted, then zero is returned.
 
+hmac(, )
+  Converts a binary input sample to a message authentication code with the 
given
+  key. The result is  a binary sample. The algorithm must be one of the
+  registered OpenSSL message digest names (e.g sha256).
+
 http_date([])
   Converts an integer supposed to contain a date since epoch to a string
   representing this date in a format suitable for use in HTTP header fields. If
diff --git a/reg-tests/sample_fetches/hashes.vtc 
b/reg-tests/sample_fetches/hashes.vtc
index 874f81e41..ca641f86c 100644
--- a/reg-tests/sample_fetches/hashes.vtc
+++ b/reg-tests/sample_fetches/hashes.vtc
@@ -38,6 +38,19 @@ haproxy h1 -conf {
 #http-response set-header x-sha2-384 "%[var(res.key),sha2(384),hex]"
 #http-response set-header x-sha2-512 "%[var(res.key),sha2(512),hex]"
 
+# OpenSSL Digest
+#http-response set-header x-digest-sha1 
"%[var(res.key),digest(sha1),hex]"
+#http-response set-header x-digest-sha224 
"%[var(res.key),digest(sha224),hex]"
+#http-response set-header x-digest-sha256 
"%[var(res.key),digest(sha256),hex]"
+#http-response set-header x-digest-sha384 
"%[var(res.key),digest(sha384),hex]"
+#http-response set-header x-digest-sha512 
"%[var(res.key),digest(sha512),hex]"
+
+# OpenSSL HMAC
+#http-response set-header x-hmac-sha1-short 
"%[var(res.key),hmac(sha1,key),hex]"
+#http-response set-header x-hmac-sha1-long 
"%[var(res.key),hmac(sha1,my_super_secret_long_key),hex]"
+#http-response set-header x-hmac-sha256-short 
"%[var(res.key),hmac(sha256,key),hex]"
+#http-response set-header x-hmac-sha256-long 
"%[var(res.key),hmac(sha256,my_super_secret_long_key),hex]"
+
 # 32-bit hashes, and their avalanche variants
 http-response set-header x-crc32   "%[var(res.key),crc32]"
 http-response set-header x-crc32-1 "%[var(res.key),crc32(1)]"
@@ -80,6 +93,15 @@ client c1 -connect ${h1_fe_sock} {
 #expect resp.http.x-sha2-256 == 
"40AFF2E9D2D8922E47AFD4648E6967497158785FBD1DA870E7110266BF944880"
 #expect resp.http.x-sha2-384 == 
"FFDAEBFF65ED05CF400F0221C4CCFB4B2104FB6A51F87E40BE6C4309386BFDEC2892E9179B34632331A59592737DB5C5"
 #expect resp.http.x-sha2-512 == 
"1E7B80BC8EDC552C8FEEB2780E111477E5BC70465FAC1A77B29B35980C3F0CE4A036A6C9462036824BD56801E62AF7E9FEBA5C22ED8A5AF877BF7DE117DCAC6D"
+#expect resp.http.x-digest-sha1 == resp.http.x-digest-sha1
+#expect resp.http.x-digest-sha224 == resp.http.x-sha2-224
+#expect resp.http.x-digest-sha256 == resp.http.x-sha2-256
+#expect resp.http.x-digest-sha384 == resp.http.x-sha2-384
+#expect resp.http.x-digest-sha512 == resp.http.x-sha2-512
+#expect resp.http.x-hmac-sha1-short == 
"98C6C3B2F2701E0C7B0AC31C09C44EFF006C802C"
+#expect resp.http.x-hmac-sha1-long == 
"0E153DC06F81DEC1352EA9394B12754C718E2600"
+#expect resp.http.x-hmac-sha256-short == 
"6AD0A89813F79E827359742225B46DC811D35E920192CFDF60F4955F14A93680"
+#expect resp.http.x-hmac-sha256-long == 
"C8E39024773AB08D937265FFAF22231F851CF00C96C6EE98DF9E0B66FFE7C089"
 expect resp.http.x-crc32 == "688229491"
 expect resp.http.x-crc32-1 == "4230317029"
 expect resp.http.x-crc32c =

Re: How to wait some time before retry?

2019-09-27 Thread Patrick Hemmer




*From:* Marco Colli [mailto:collimarc...@gmail.com]
*Sent:* Friday, September 27, 2019, 07:21 EDT
*To:* HAProxy 
*Subject:* How to wait some time before retry?

Still have this issue and I cannot find a solution. It would be great 
to have an option "wait time before retry" in the next versions of 
HAProxy (instead of the fixed value of 1 sec).


On Mon, Sep 16, 2019 at 2:03 PM Marco Colli <mailto:collimarc...@gmail.com>wrote:


Hello!

I have a question about HAProxy configuration. Maybe someone has a
solution ;)

I have a HAProxy (v2.0) load balancer in front of many web servers.

When I restart the web servers the TCP socket remains closed for a
few seconds (~10s). For this reason I would like to retry failed
attempts to connect after some seconds.

I already use |option redispatch|, however it seems that does not
solve my issue. The problem is that the request is retried
immediately (after 1s), thus causing all the retries to fail. From
the HAProxy docs:

In order to avoid immediate reconnections to a server which is
restarting, a turn-around timer of min("timeout connect", one
second) is applied before a retry occurs.

Is there any option to wait some more time (e.g. 10s) before
retrying? Or do you have any other solution?




Not the cleanest solution, but something that could work would be to add 
a lua action to sleep for 10 seconds on the response when you have a 
connect error, and then override the response to a 307 (or perhaps 302) 
redirect back to the same location. This will then cause the browser to 
retry the request.



-Patrick


Re: [PATCH] improving github experience, kindly ask people to reproduce bugs on latest haproxy

2019-09-20 Thread Patrick Hemmer




*From:* Илья Шипицин [mailto:chipits...@gmail.com]
*Sent:* Thursday, September 19, 2019, 15:10 EDT
*To:* HAProxy 
*Subject:* [PATCH] improving github experience, kindly ask people to 
reproduce bugs on latest haproxy



hello,

please find attached patch

Ilya Shipitsin
I dunno, I've personally never been fond of it when bug reporters are 
blindly asked to upgrade to the latest version. Sometimes the request is 
justified, such as when the project maintainers have reason to believe 
the bug is fixed, or if the version is years old. But otherwise it can 
causes difficulties for the reporter. In corporate environments, it can 
be difficult to perform such upgrades. Sometimes these issues are only 
reproducible in production environments. So by asking them to upgrade, 
you're making them go through the difficulty, and potentially cause 
impact to their clients. And because that process can take a while, it's 
possible that by the time they do complete the upgrade, another version 
has been released.


I personally also find the use of heavy bug templates, with nuanced 
little checkboxes to be annoying. In this case more so because we 
already ask them to provide the version information, which answers the 
question the checkbox is for. And the checkbox "yes i'm on the latest" 
might be accurate at the time of submission, but can become out of date.


Now all that said, I'm not against encouraging people to try a later 
version if available. Just that I don't think it should be the expectation.


-Patrick


[RFC] MINOR: attempt to insert into priority queue when full

2019-09-12 Thread Patrick Hemmer
This is a draft patch which essentially allows a high priority request 
to replace a low priority request when the queue is full.


Currently if a high priority request comes along, and the destination 
queue is full, the request gets rejected (or redispatched if possible). 
This change allows inserting into the queue if there are lower priority 
requests present. When doing so, the lowest priority request is evicted 
to make room.


The intent is for that evicted request to be handled as if it just came 
in. Meaning if there were a brand new request coming in, and the 
configuration were such that the request should be rejected, then the 
evicted request should be rejected. If redispatch is enabled a new 
request would be sent to a different server, and so the evicted request 
should be as well.



Now as for why this is tagged RFC: The implementation for the handling 
of the evicted request is bad. If you notice inside pendconn_displace(), 
the section of code that handles this (lines 498-505) has no business 
being there. Those operations should be handled higher up. It also 
doesn't work as intended, as instead of responding to the client with a 
503, it just kills the connection.


However I'm having difficulty finding the appropriate way to do this, 
and could use some guidance. I've tried several different things, and 
none of the behaviors are quite right.
The simplest solution of just performing __pendconn_unlink() and then 
waking the task results in the request being redispatched. The higher 
level code assumes that if the request was in a queue, and is now no 
longer in a queue, then redispatch is the appropriate action.


Thanks

-Patrick
From a3c8ba92a05ec877662359f963ece0cfa82051f8 Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Thu, 12 Sep 2019 22:56:51 -0400
Subject: [PATCH] MINOR: attempt to insert into priority queue when full

This makes it so that when a queue (server or proxy) is full, that we try to
insert into the queue and evict a request of lower priority.

The evicted request will either be redispatched if `option redispatch` is
enabled, or rejected if not.
---
 include/proto/queue.h |   1 +
 src/backend.c |   3 +-
 src/queue.c   | 119 ++
 3 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/include/proto/queue.h b/include/proto/queue.h
index a7ab63b35..156bf3964 100644
--- a/include/proto/queue.h
+++ b/include/proto/queue.h
@@ -37,6 +37,7 @@
 extern struct pool_head *pool_head_pendconn;
 
 struct pendconn *pendconn_add(struct stream *strm);
+int pendconn_displace(struct stream *strm);
 int pendconn_dequeue(struct stream *strm);
 void process_srv_queue(struct server *s);
 unsigned int srv_dynamic_maxconn(const struct server *s);
diff --git a/src/backend.c b/src/backend.c
index 1b01536c1..56340d2de 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -976,7 +976,8 @@ int assign_server_and_queue(struct stream *s)
(srv->nbpend || srv->served >= srv_dynamic_maxconn(srv))) {
 
if (srv->maxqueue > 0 && srv->nbpend >= srv->maxqueue)
-   return SRV_STATUS_FULL;
+   // queue is full. see if priority allows us to 
insert
+   return pendconn_displace(s);
 
p = pendconn_add(s);
if (p)
diff --git a/src/queue.c b/src/queue.c
index 30b7ef056..ea015272a 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -185,6 +185,33 @@ void pendconn_unlink(struct pendconn *p)
pendconn_queue_unlock(p);
 }
 
+/* Comapres 2 pendconn queue priority keys.
+ *
+ * Returns :
+ *   -1 if k1 < k2
+ *   0  if k1 == k2
+ *   1  if k1 > k2
+ */
+static int key_cmp(u32 k1, u32 k2)
+{
+   if (KEY_CLASS(k1) < KEY_CLASS(k2))
+   return -1;
+   if (KEY_CLASS(k1) > KEY_CLASS(k2))
+   return 1;
+
+   if (k1 < NOW_OFFSET_BOUNDARY())
+   k1 += 0x10; // key in the future
+   if (k2 < NOW_OFFSET_BOUNDARY())
+   k2 += 0x10; // key in the future
+
+   if (k1 < k2)
+   return -1;
+   if (k1 > k2)
+   return 1;
+
+   return 0;
+}
+
 /* Retrieve the first pendconn from tree . Classes are always
  * considered first, then the time offset. The time does wrap, so the
  * lookup is performed twice, one to retrieve the first class and a second
@@ -212,6 +239,31 @@ static struct pendconn *pendconn_first(struct eb_root 
*pendconns)
return eb32_entry(node2, struct pendconn, node);
 }
 
+/* Retrieve the last pendconn from tree .
+ * Follows the same semantics as pendconn_first.
+ */
+static struct pendconn *pendconn_last(struct eb_root *pendconns)
+{
+   struct eb32_node *node, *node2 = NULL;
+   u32 key;
+
+   node = eb32_last(pendconns);
+   if (!node)
+   return NULL;
+
+   key = KEY_CL

Re: fullconn not working

2019-07-16 Thread Patrick Hemmer




*From:* Jerome Magnin [mailto:jmag...@haproxy.com]
*Sent:* Tuesday, July 16, 2019, 10:19 EDT
*To:* Patrick Hemmer 
*Cc:* Pavlos Parissis , haproxy@formilux.org
*Subject:* fullconn not working


Hi Patrick,

On Tue, Jul 16, 2019 at 09:40:31AM -0400, Patrick Hemmer wrote:


*From:* Pavlos Parissis [mailto:pavlos.paris...@gmail.com]
*Sent:* Tuesday, July 16, 2019, 09:32 EDT
*To:* haproxy@formilux.org
*Cc:* Patrick Hemmer 
*Subject:* fullconn not working


On Παρασκευή, 28 Ιουνίου 2019 5:50:48 Μ.Μ. CEST Patrick Hemmer wrote:

I'm trying to get fullconn working, and can't seem to do so. I dunno if
it's a bug, or if it's my understanding that's wrong.
Basically my goal is to prevent the cumulative total of all connections
to all servers in a pool from exceeding a certain value.
For example I might have 10 servers, each with a maxconn of 10. But I
want to configure haproxy with a pool-wide limit of 50, so that even if
the connections are well distributed and no one server is maxed out,
after 50 connections to all servers, haproxy will still start to queue
instead.

fullconn seems like the right way to accomplish this, however I cannot
get it to work. I've tried a simple setup of 2 servers, each with
`maxconn 3`, and then a backend `fullconn 2`, which should result in
queuing after 2 simultaneous connections, however it doesn't. If I send
4 connections, all 4 are simultaneously sent to the backend servers.

Here's my test config:
defaults
   log 127.0.0.1:1234 daemon
   mode http
   option httplog
   timeout queue 5s
frontend f1
   bind :8001
   default_backend b1
backend b1
   fullconn 2
   server s1 127.0.0.1:8081 minconn 1 maxconn 3
   server s2 127.0.0.1:8081 minconn 1 maxconn 3

Here's how I test:
for i in {1..4}; do curl "http://localhost:8001/?sleep=2=$i; & done

And here's the logs:
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55119
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - - 
4/4/3/2/0 0/0 "GET /?sleep=2=3 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55117
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - - 
4/4/2/1/0 0/0 "GET /?sleep=2=4 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55118
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - - 
4/4/1/2/0 0/0 "GET /?sleep=2=1 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55120
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - - 
4/4/0/1/0 0/0 "GET /?sleep=2=2 HTTP/1.1"



Your e-mail client mangled above log lines and as a result they are bit 
unreadable.
The 4th field from `4/4/3/2/0`  is srv_conn  *2* which is below the maxconn of 
*3*, so haproxy did
the right thing as it didn't allow more than *full_conn* connections to be 
concurrently opened
against the server.

Cheers,
Pavlos

maxconn and fullconn are different settings.
maxconn: 
https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#maxconn%20(Server%20and%20default-server%20options)
fullconn:
https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#fullconn

-Patrick

fullconn is not used to set a limit on the amount of connections handled by the
backend. It is used to have a 'dynamic' maxconn value on server lines.

this dymanic maxconn value will never be below minconn, and never higher than
maxconn. When the amount of connections handled by backend is between 0 and
fullconn, this dynamic maxconn value is somewhere between minconn and maxconn,
proportionnate to where we are between 0 and fullconn. When fullconn is reached,
dynamic maxconn equals the maxconn you set on server line.

With the values you set, when you reach 2 connections at backend level, servers
will allow 3 at most, each.

Jérôme

Thanks, I think I'm following now. My understanding was backwards.
I'm guessing the use case for this is so that you have maxconn at a 
value where servers have a good response time. But then if you start 
queueing too much, then maxconn is raised, trading slower response time 
for higher throughput.



So my next question, is there any way to set a backend connection limit 
(after which connections get queued)? I want to limit the number of 
active connections across the whole pool, regardless of the number of 
servers, or what the limit on each server is.


The reason is that there are shared resources (e.g. a database, NAS 
filesystem, etc) behind a pool, and that shared resource can only handle 
so much load. We can divide the cumulative limit across the number of 
servers in the pool, but if some of the servers are out of the pool, 
then that limit shrinks and we're not utilizing the full capacity of the 
shared resources.



-Patrick


Re: fullconn not working

2019-07-16 Thread Patrick Hemmer




*From:* Pavlos Parissis [mailto:pavlos.paris...@gmail.com]
*Sent:* Tuesday, July 16, 2019, 09:32 EDT
*To:* haproxy@formilux.org
*Cc:* Patrick Hemmer 
*Subject:* fullconn not working


On Παρασκευή, 28 Ιουνίου 2019 5:50:48 Μ.Μ. CEST Patrick Hemmer wrote:

I'm trying to get fullconn working, and can't seem to do so. I dunno if
it's a bug, or if it's my understanding that's wrong.
Basically my goal is to prevent the cumulative total of all connections
to all servers in a pool from exceeding a certain value.
For example I might have 10 servers, each with a maxconn of 10. But I
want to configure haproxy with a pool-wide limit of 50, so that even if
the connections are well distributed and no one server is maxed out,
after 50 connections to all servers, haproxy will still start to queue
instead.

fullconn seems like the right way to accomplish this, however I cannot
get it to work. I've tried a simple setup of 2 servers, each with
`maxconn 3`, and then a backend `fullconn 2`, which should result in
queuing after 2 simultaneous connections, however it doesn't. If I send
4 connections, all 4 are simultaneously sent to the backend servers.

Here's my test config:
defaults
  log 127.0.0.1:1234 daemon
  mode http
  option httplog
  timeout queue 5s
frontend f1
  bind :8001
  default_backend b1
backend b1
  fullconn 2
  server s1 127.0.0.1:8081 minconn 1 maxconn 3
  server s2 127.0.0.1:8081 minconn 1 maxconn 3

Here's how I test:
for i in {1..4}; do curl "http://localhost:8001/?sleep=2=$i; & done

And here's the logs:
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55119
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - - 
4/4/3/2/0 0/0 "GET /?sleep=2=3 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55117
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - - 
4/4/2/1/0 0/0 "GET /?sleep=2=4 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55118
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - - 
4/4/1/2/0 0/0 "GET /?sleep=2=1 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55120
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - - 
4/4/0/1/0 0/0 "GET /?sleep=2=2 HTTP/1.1"



Your e-mail client mangled above log lines and as a result they are bit 
unreadable.
The 4th field from `4/4/3/2/0`  is srv_conn  *2* which is below the maxconn of 
*3*, so haproxy did
the right thing as it didn't allow more than *full_conn* connections to be 
concurrently opened
against the server.

Cheers,
Pavlos

maxconn and fullconn are different settings.
maxconn: 
https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#maxconn%20(Server%20and%20default-server%20options)
fullconn: 
https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#fullconn


-Patrick


Re: fullconn not working

2019-07-16 Thread Patrick Hemmer




*From:* Patrick Hemmer [mailto:hapr...@stormcloud9.net]
*Sent:* Friday, June 28, 2019, 11:50 EDT
*To:* HAProxy 
*Subject:* fullconn not working

I'm trying to get fullconn working, and can't seem to do so. I dunno 
if it's a bug, or if it's my understanding that's wrong.
Basically my goal is to prevent the cumulative total of all 
connections to all servers in a pool from exceeding a certain value.
For example I might have 10 servers, each with a maxconn of 10. But I 
want to configure haproxy with a pool-wide limit of 50, so that even 
if the connections are well distributed and no one server is maxed 
out, after 50 connections to all servers, haproxy will still start to 
queue instead.


fullconn seems like the right way to accomplish this, however I cannot 
get it to work. I've tried a simple setup of 2 servers, each with 
`maxconn 3`, and then a backend `fullconn 2`, which should result in 
queuing after 2 simultaneous connections, however it doesn't. If I 
send 4 connections, all 4 are simultaneously sent to the backend servers.


Here's my test config:
defaults
    log 127.0.0.1:1234 daemon
    mode http
    option httplog
    timeout queue 5s
frontend f1
    bind :8001
    default_backend b1
backend b1
    fullconn 2
    server s1 127.0.0.1:8081 minconn 1 maxconn 3
    server s2 127.0.0.1:8081 minconn 1 maxconn 3

Here's how I test:
for i in {1..4}; do curl "http://localhost:8001/?sleep=2=$i; & done

And here's the logs:
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55119 
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - -  
4/4/3/2/0 0/0 "GET /?sleep=2=3 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55117 
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - -  
4/4/2/1/0 0/0 "GET /?sleep=2=4 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55118 
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - -  
4/4/1/2/0 0/0 "GET /?sleep=2=1 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55120 
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - -  
4/4/0/1/0 0/0 "GET /?sleep=2=2 HTTP/1.1"



So am I misunderstanding how fullconn works? Or is there a bug?
I've tested with 2.0.1, 1.9.8, and 1.8.13.

-Patrick


Anyone with any thoughts on this? Anyone using fullconn successfully?

As an additional item of note that makes me suspect this is a bug even 
more is that when viewing the stats page, it shows the number of 
sessions is greater than the limit.



-Patrick


Re: haproxy inappropriately sending rst_stream on http/2

2019-07-08 Thread Patrick Hemmer




*From:* Patrick Hemmer [mailto:hapr...@stormcloud9.net]
*Sent:* Wednesday, June 26, 2019, 08:06 EDT
*To:* haproxy@formilux.org 
*Subject:* haproxy inappropriately sending rst_stream on http/2

I'm running haproxy 1.9.8 and am having an issue where haproxy is 
sending a http/2 rst_stream message to the client for some reason.


When I look in the haproxy logs, the state termination flags are 
"CD--". However I know the client didn't abort the request as I have a 
packet capture showing the client did no such thing. Additionally 
there are other requests on the same connection, both before & after 
the one that gets reset, which go through fine.


Willy, I'm going to send both the logs and packet capture off-list.

-Patrick

So I sent the information to Willy, but I'm guessing he's occupied with 
other things as I haven't heard back (which is perfectly fine, this is 
an open source project with no support contract after all). But if there 
is someone else in the HAProxy org I can send the debug info to, I can 
do that. I just don't want to post it publicly.


Thanks

-Patrick


Re: DOC: Suggest to replace the netstat commands

2019-07-08 Thread Patrick Hemmer




*From:* Alain Belkadi [mailto:xigu...@linuxbeach.be]
*Sent:* Monday, July 8, 2019, 10:51 EDT
*To:* haproxy@formilux.org
*Subject:* DOC: Suggest to replace the netstat commands



Hello,

As the "netstat" command is deprecated since a long time (1), I 
suggest to replace it with other commands like ss and ip.


I've made a first patch for this. As the number of columns is higher 
than the 80 standard, I've made a second patch with less long lines 
... but that don't fit inside 80 chars and if I remove more spaces 
that don't looks good.


(1) https://en.wikipedia.org/wiki/Netstat

Regards,

This raises a potential issue. Netstat is deprecated on Linux yes, but 
not other OSs (which HAProxy runs on). However the example usage that 
was provided ("netstat -ltnp") is the Linux compatible flags, so the doc 
was already somewhat Linux specific. However other references, such as 
"netstat -i", are cross-platform.


So where do we draw the line on being Linux-specific in our 
documentation, vs. OS agnostic?


-Patrick


fullconn not working

2019-06-28 Thread Patrick Hemmer
I'm trying to get fullconn working, and can't seem to do so. I dunno if 
it's a bug, or if it's my understanding that's wrong.
Basically my goal is to prevent the cumulative total of all connections 
to all servers in a pool from exceeding a certain value.
For example I might have 10 servers, each with a maxconn of 10. But I 
want to configure haproxy with a pool-wide limit of 50, so that even if 
the connections are well distributed and no one server is maxed out, 
after 50 connections to all servers, haproxy will still start to queue 
instead.


fullconn seems like the right way to accomplish this, however I cannot 
get it to work. I've tried a simple setup of 2 servers, each with 
`maxconn 3`, and then a backend `fullconn 2`, which should result in 
queuing after 2 simultaneous connections, however it doesn't. If I send 
4 connections, all 4 are simultaneously sent to the backend servers.


Here's my test config:
defaults
    log 127.0.0.1:1234 daemon
    mode http
    option httplog
    timeout queue 5s
frontend f1
    bind :8001
    default_backend b1
backend b1
    fullconn 2
    server s1 127.0.0.1:8081 minconn 1 maxconn 3
    server s2 127.0.0.1:8081 minconn 1 maxconn 3

Here's how I test:
for i in {1..4}; do curl "http://localhost:8001/?sleep=2=$i; & done

And here's the logs:
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55119 
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - -  
4/4/3/2/0 0/0 "GET /?sleep=2=3 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55117 
[28/Jun/2019:11:37:45.658] f1 b1/s2 0/0/0/2003/2003 200 75 - -  
4/4/2/1/0 0/0 "GET /?sleep=2=4 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55118 
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - -  
4/4/1/2/0 0/0 "GET /?sleep=2=1 HTTP/1.1"
<30>Jun 28 11:37:47 haproxy[75322]: 127.0.0.1:55120 
[28/Jun/2019:11:37:45.658] f1 b1/s1 0/0/0/2003/2003 200 75 - -  
4/4/0/1/0 0/0 "GET /?sleep=2=2 HTTP/1.1"



So am I misunderstanding how fullconn works? Or is there a bug?
I've tested with 2.0.1, 1.9.8, and 1.8.13.

-Patrick



Re: Case Sensitive Headers

2019-06-27 Thread Patrick Hemmer




*From:* Luke Seelenbinder [mailto:l...@sermonaudio.com]
*Sent:* Wednesday, June 26, 2019, 10:07 EDT
*To:* HAProxy 
*Subject:* Case Sensitive Headers


Hello List,

I have a painful case of noncompliance to report and figure out how to 
fix.


When HTX is enabled, all headers are returned in lower case (e.g., 
content-length, date, etc.). This is obviously fine and within spec. 
Unfortunately, I'm using a rather frustrating piece of software 
(Wowza) that talks to an haproxy instance and Wowza requires that the 
content-length header is always camel case, i.e., Content-Length, 
otherwise requests fail.


I tried using http-response set-header Content-Length 
%[res.hdr(content-length)] if { res.hdr(content-length) -m found } to 
force the value to upper case, but that didn't help.


This is very obviously a case of badly behaving software and not a 
problem with HAProxy, but I'm wondering if there's any other way to 
force that header to Content-Length without turning HTX off.


Thanks for any ideas!

Best,
Luke

—
*Luke Seelenbinder*
SermonAudio.com <http://sermonaudio.com> | Senior Software Engineer


This is just a stab in the dark, but try deleting the header, then 
adding it back. For example


http-response set-var(res.conlen) res.hdr(content-length)
http-response del-header content-length
http-response set-header Content-Length %[var(res.conlen)] if { 
var(res.conlen) -m found }


-Patrick


haproxy inappropriately sending rst_stream on http/2

2019-06-26 Thread Patrick Hemmer
I'm running haproxy 1.9.8 and am having an issue where haproxy is 
sending a http/2 rst_stream message to the client for some reason.


When I look in the haproxy logs, the state termination flags are "CD--". 
However I know the client didn't abort the request as I have a packet 
capture showing the client did no such thing. Additionally there are 
other requests on the same connection, both before & after the one that 
gets reset, which go through fine.


Willy, I'm going to send both the logs and packet capture off-list.

-Patrick





Re: [PATCH] MINOR: SSL: add client/server random sample fetches

2019-06-04 Thread Patrick Hemmer




*From:* Patrick Hemmer [mailto:hapr...@stormcloud9.net]
*Sent:* Tuesday, June 4, 2019, 16:38 EDT
*To:* haproxy@formilux.org
*Subject:* [PATCH] MINOR: SSL: add client/server random sample fetches

Re-send of earlier patch due to formatting issues (upgraded 
thunderbird and lost a bunch of stuff :-( ).

As an attachment this time, so should be safe.

-Patrick
The updated patch fixes the documentation to be in alphabetical order. 
Got carried away with putting the doc in the same order the code is in.


-Patrick
From 39238b4840d409b5dcf198f2e03b5a58bb718d4a Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Tue, 4 Jun 2019 08:13:03 -0400
Subject: [PATCH] MINOR: SSL: add client/server random sample fetches

This adds 4 sample fetches:
- ssl_fc_client_random
- ssl_fc_server_random
- ssl_bc_client_random
- ssl_bc_server_random

These fetches retrieve the client or server random value sent during the
handshake.

Their use is to be able to decrypt traffic sent using ephemeral ciphers. Tools
like wireshark expect a TLS log file with lines in a few known formats
(https://code.wireshark.org/review/gitweb?p=wireshark.git;a=blob;f=epan/dissectors/packet-tls-utils.c;h=28a51fb1fb029eae5cea52d37ff5b67d9b11950f;hb=HEAD#l5209).
Previously the only format supported using data retrievable from HAProxy state
was the one utilizing the Session-ID. However an SSL/TLS session ID is
optional, and thus cannot be relied upon for this purpose.

This change introduces the ability to extract the client random instead which
can be used for one of the other formats. The change also adds the ability to
extract the server random, just in case it might have some other use, as the
code change to support this was trivial.
---
 doc/configuration.txt | 20 
 src/ssl_sock.c| 35 +++
 2 files changed, 55 insertions(+)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 074a7fffe..e6e6285a6 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -15430,6 +15430,11 @@ ssl_bc_cipher : string
   Returns the name of the used cipher when the outgoing connection was made
   over an SSL/TLS transport layer.
 
+ssl_bc_client_random : binary
+  Returns the client random of the back connection when the incoming connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
 ssl_bc_is_resumed : boolean
   Returns true when the back connection was made over an SSL/TLS transport
   layer and the newly created SSL session was resumed using a cached
@@ -15454,6 +15459,11 @@ ssl_bc_unique_id : binary
   returns the TLS unique ID as defined in RFC5929 section 3. The unique id
   can be encoded to base64 using the converter: "ssl_bc_unique_id,base64".
 
+ssl_bc_server_random : binary
+  Returns the server random of the back connection when the incoming connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
 ssl_bc_session_id : binary
   Returns the SSL ID of the back connection when the outgoing connection was
   made over an SSL/TLS transport layer. It is useful to log if we want to know
@@ -15675,6 +15685,11 @@ ssl_fc_cipherlist_xxh : integer
   "tune.ssl.capture-cipherlist-size" is set greater than 0, however the hash
   take in account all the data of the cipher list.
 
+ssl_fc_client_random : binary
+  Returns the client random of the front connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
 ssl_fc_has_crt : boolean
   Returns true if a client certificate is present in an incoming connection 
over
   SSL/TLS transport layer. Useful if 'verify' statement is set to 'optional'.
@@ -15719,6 +15734,11 @@ ssl_fc_unique_id : binary
   returns the TLS unique ID as defined in RFC5929 section 3. The unique id
   can be encoded to base64 using the converter: "ssl_bc_unique_id,base64".
 
+ssl_fc_server_random : binary
+  Returns the server random of the front connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
 ssl_fc_session_id : binary
   Returns the SSL ID of the front connection when the incoming connection was
   made over an SSL/TLS transport layer. It is useful to stick a given client to
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 2eb344dfa..fb7e96bf9 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -7195,6 +7195,37 @@ smp_fetch_ssl_fc_session_id(const struct arg *args, 
struct sample *smp, const ch
 
 
 #if HA_OPENSSL_VERSION_NUMBER >

[PATCH] MINOR: SSL: add client/server random sample fetches

2019-06-04 Thread Patrick Hemmer
Re-send of earlier patch due to formatting issues (upgraded thunderbird 
and lost a bunch of stuff :-( ).

As an attachment this time, so should be safe.

-Patrick
From 0947dc1faf7a0a90631adcebc2e65fc191da8473 Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Tue, 4 Jun 2019 08:13:03 -0400
Subject: [PATCH] MINOR: SSL: add client/server random sample fetches

This adds 4 sample fetches:
- ssl_fc_client_random
- ssl_fc_server_random
- ssl_bc_client_random
- ssl_bc_server_random

These fetches retrieve the client or server random value sent during the
handshake.

Their use is to be able to decrypt traffic sent using ephemeral ciphers. Tools
like wireshark expect a TLS log file with lines in a few known formats
(https://code.wireshark.org/review/gitweb?p=wireshark.git;a=blob;f=epan/dissectors/packet-tls-utils.c;h=28a51fb1fb029eae5cea52d37ff5b67d9b11950f;hb=HEAD#l5209).
Previously the only format supported using data retrievable from HAProxy state
was the one utilizing the Session-ID. However an SSL/TLS session ID is
optional, and thus cannot be relied upon for this purpose.

This change introduces the ability to extract the client random instead which
can be used for one of the other formats. The change also adds the ability to
extract the server random, just in case it might have some other use, as the
code change to support this was trivial.
---
 doc/configuration.txt | 20 
 src/ssl_sock.c| 35 +++
 2 files changed, 55 insertions(+)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 074a7fffe..f1325ea3f 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -15459,6 +15459,16 @@ ssl_bc_session_id : binary
   made over an SSL/TLS transport layer. It is useful to log if we want to know
   if session was reused or not.
 
+ssl_bc_client_random : binary
+  Returns the client random of the back connection when the incoming connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
+ssl_bc_server_random : binary
+  Returns the server random of the back connection when the incoming connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
 ssl_bc_session_key : binary
   Returns the SSL session master key of the back connection when the outgoing
   connection was made over an SSL/TLS transport layer. It is useful to decrypt
@@ -15725,6 +15735,16 @@ ssl_fc_session_id : binary
   a server. It is important to note that some browsers refresh their session ID
   every few minutes.
 
+ssl_fc_client_random : binary
+  Returns the client random of the front connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
+ssl_fc_server_random : binary
+  Returns the server random of the front connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or BoringSSL.
+
 ssl_fc_session_key : binary
   Returns the SSL session master key of the front connection when the incoming
   connection was made over an SSL/TLS transport layer. It is useful to decrypt
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 2eb344dfa..fb7e96bf9 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -7195,6 +7195,37 @@ smp_fetch_ssl_fc_session_id(const struct arg *args, 
struct sample *smp, const ch
 
 
 #if HA_OPENSSL_VERSION_NUMBER >= 0x1010L || defined(OPENSSL_IS_BORINGSSL)
+static int
+smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, const char 
*kw, void *private)
+{
+   struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) 
:
+   smp->strm ? 
cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
+   struct buffer *data;
+   struct ssl_sock_ctx *ctx;
+
+   if (!conn || !conn->xprt_ctx || conn->xprt != _sock)
+   return 0;
+   ctx = conn->xprt_ctx;
+
+   data = get_trash_chunk();
+   if (kw[7] == 'c')
+   data->data = SSL_get_client_random(ctx->ssl,
+   
(unsigned char *) data->area,
+   
data->size);
+   else
+   data->data = SSL_get_server_random(ctx->ssl,
+   
(unsigned char *) data->area,
+   

Re: http_first_req not working with http2

2019-06-04 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Tuesday, June 4, 2019, 10:08 EDT
*To:* Patrick Hemmer 
*Cc:* haproxy@formilux.org
*Subject:* http_first_req not working with http2


Hi Patrick,

On Mon, Jun 03, 2019 at 05:21:26PM -0400, Patrick Hemmer wrote:

As subject says, it appears that the http_first_req sample is not working
with http2.

Indeed, the first request in H1 is special in that it is not
automatically retryable. In H2 it's different, all requests are
totally independant and there is not even any real ordering. Since
it is possible to use GOAWAY to cleanly close a connection, no H2
request suffers from the limitations of the first H1 request, so
none of them is marked first. At the very least this should be
mentioned in the doc.

Do you have a particular use case that relies on this and which would
need any form of emulation of this older behaviour ? I couldn't find
any but maybe there are.

Thanks,
Willy


The use case was that I was trying to log SSL data (via a Lua script) 
when the connection is first established. If the frontend is operating 
in http mode (as opposed to tcp), we can only apply actions on receipt 
of a request, and not after connection is established. Thus I was trying 
to use http_first_req to trigger the action only on the first request.


I suppose an alternate that might work would be to add support for using 
Lua actions with `tcp-request session`.


-Patrick


[PATCH] MINOR: SSL: add client/server random sample fetches

2019-06-04 Thread Patrick Hemmer
This adds 4 sample fetches:
- ssl_fc_client_random
- ssl_fc_server_random
- ssl_bc_client_random
- ssl_bc_server_random

These fetches retrieve the client or server random value sent during the
handshake.

Their use is to be able to decrypt traffic sent using ephemeral ciphers. 
Tools
like wireshark expect a TLS log file with lines in a few known formats
(https://code.wireshark.org/review/gitweb?p=wireshark.git;a=blob;f=epan/dissectors/packet-tls-utils.c;h=28a51fb1fb029eae5cea52d37ff5b67d9b11950f;hb=HEAD#l5209).
Previously the only format supported using data retrievable from HAProxy 
state
was the one utilizing the Session-ID. However an SSL/TLS session ID is
optional, and thus cannot be relied upon for this purpose.

This change introduces the ability to extract the client random instead 
which
can be used for one of the other formats. The change also adds the 
ability to
extract the server random, just in case it might have some other use, as the
code change to support this was trivial.
---
  doc/configuration.txt | 20 
  src/ssl_sock.c| 35 +++
  2 files changed, 55 insertions(+)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 074a7fffe..f1325ea3f 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -15459,6 +15459,16 @@ ssl_bc_session_id : binary
made over an SSL/TLS transport layer. It is useful to log if we want 
to know
if session was reused or not.
  +ssl_bc_client_random : binary
+  Returns the client random of the back connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt 
traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or 
BoringSSL.
+
+ssl_bc_server_random : binary
+  Returns the server random of the back connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt 
traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or 
BoringSSL.
+
  ssl_bc_session_key : binary
Returns the SSL session master key of the back connection when the 
outgoing
connection was made over an SSL/TLS transport layer. It is useful to 
decrypt
@@ -15725,6 +15735,16 @@ ssl_fc_session_id : binary
a server. It is important to note that some browsers refresh their 
session ID
every few minutes.
  +ssl_fc_client_random : binary
+  Returns the client random of the front connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt 
traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or 
BoringSSL.
+
+ssl_fc_server_random : binary
+  Returns the server random of the front connection when the incoming 
connection
+  was made over an SSL/TLS transport layer. It is useful to to decrypt 
traffic
+  sent using ephemeral ciphers. This requires OpenSSL >= 1.1.0, or 
BoringSSL.
+
  ssl_fc_session_key : binary
Returns the SSL session master key of the front connection when the 
incoming
connection was made over an SSL/TLS transport layer. It is useful to 
decrypt
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 2eb344dfa..fb7e96bf9 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -7195,6 +7195,37 @@ smp_fetch_ssl_fc_session_id(const struct arg 
*args, struct sample *smp, const ch
#if HA_OPENSSL_VERSION_NUMBER >= 0x1010L || 
defined(OPENSSL_IS_BORINGSSL)
+static int
+smp_fetch_ssl_fc_random(const struct arg *args, struct sample *smp, 
const char *kw, void *private)
+{
+   struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) 
:
+   smp->strm ? 
cs_conn(objt_cs(smp->strm->si[1].end)) : NULL;
+   struct buffer *data;
+   struct ssl_sock_ctx *ctx;
+
+   if (!conn || !conn->xprt_ctx || conn->xprt != _sock)
+   return 0;
+   ctx = conn->xprt_ctx;
+
+   data = get_trash_chunk();
+   if (kw[7] == 'c')
+   data->data = SSL_get_client_random(ctx->ssl,
+   
(unsigned char *) data->area,
+   
data->size);
+   else
+   data->data = SSL_get_server_random(ctx->ssl,
+   
(unsigned char *) data->area,
+   
data->size);
+   if (!data->data)
+   return 0;
+
+   smp->flags = 0;
+   smp->data.type = SMP_T_BIN;
+   smp->data.u.str = *data;
+
+   return 1;
+}
+
  static int
  smp_fetch_ssl_fc_session_key(const struct arg *args, struct sample 
*smp, const char *kw, void *private)
  {
@@ -9395,6 +9426,8 @@ static struct sample_fetch_kw_list 

unset-var doesn't support conditions

2019-06-03 Thread Patrick Hemmer
It appears that all usages of unset-var don't support conditions. 
Meaning none of the following work:


http-request unset-var(txn.foo) if { always_true }
tcp-request content unset-var(txn.foo) if { always_true }
etc.

The error presented is:
[ALERT] 153/175307 (58641) : parsing [haproxy-minimal.cfg:12] : error 
detected in frontend 'f1' while parsing 'http-request 
unset-var(txn.foo)' rule :

 fetch method not supported.
[ALERT] 153/175307 (58641) : Error(s) found in configuration file : 
haproxy-minimal.cfg



The documentation indicates this should be possible:

http-request unset-var() [ { if | unless }  ]

This is experienced with version 1.9.8

-Patrick



segfault in tcp-request session set-var

2019-06-03 Thread Patrick Hemmer
In haproxy 1.9.8, if you do `tcp-request session set-var()` with a 
variable in any scope other than sess, it segfaults.

For example:
tcp-request session set-var(txn.foo) ...
tcp-request session set-var(req.foo) ...

* thread #1, queue = 'com.apple.main-thread', stop reason = 
EXC_BAD_ACCESS (code=1, address=0x268)
    frame #0: 0x00010019c6a7 
haproxy`sample_store_stream(name="foo", scope=SCOPE_TXN, 
smp=0x7ffeefbfef48) at vars.c:442

   439         case SCOPE_RES:
   440         default: vars = >strm->vars_reqres; break;
   441         }
-> 442         if (vars->scope != scope)
   443             return 0;
   444
   445         HA_RWLOCK_WRLOCK(VARS_LOCK, >rwlock);
Target 0: (haproxy) stopped.

-Patrick



Re: http_first_req not working with http2

2019-06-03 Thread Patrick Hemmer




*From:* Patrick Hemmer [mailto:hapr...@stormcloud9.net]
*Sent:* Monday, June 3, 2019, 17:21 EDT
*To:* haproxy@formilux.org
*Subject:* http_first_req not working with http2

As subject says, it appears that the http_first_req sample is not 
working with http2.


Config:
  frontend f1
    bind :8000
    option http-use-htx
    log-format http_first_req=%[http_first_req]

With `curl http://localhost:8000`
Outputs:
  <30>Jun  3 17:16:36 haproxy[47767]: http_first_req=1


Where as,
Config:
  frontend f1
    bind :8000 proto h2
    option http-use-htx
    log-format http_first_req=%[http_first_req]

With `curl --http2-prior-knowledge http://localhost:8000`
Outputs:
  <30>Jun  3 17:16:51 haproxy[47829]: http_first_req=0


-Patrick


Oh, forgot the version. 1.9.8

-Patrick


http_first_req not working with http2

2019-06-03 Thread Patrick Hemmer
As subject says, it appears that the http_first_req sample is not 
working with http2.


Config:
  frontend f1
    bind :8000
    option http-use-htx
    log-format http_first_req=%[http_first_req]

With `curl http://localhost:8000`
Outputs:
  <30>Jun  3 17:16:36 haproxy[47767]: http_first_req=1


Where as,
Config:
  frontend f1
    bind :8000 proto h2
    option http-use-htx
    log-format http_first_req=%[http_first_req]

With `curl --http2-prior-knowledge http://localhost:8000`
Outputs:
  <30>Jun  3 17:16:51 haproxy[47829]: http_first_req=0


-Patrick



Lua logging to syslog & not stderr

2019-06-03 Thread Patrick Hemmer
Is there a way to have Lua log to syslog only, and not to stderr? When I 
call `TXN.log(...)`, the message shows up in syslog AND stderr.


The Lua documentation implies this is possible as it has this statement 
(http://www.arpalert.org/src/haproxy-lua-api/1.9/index.html):


> The log is sent, according with the HAProxy configuration file, on 
the default syslog server if it is configured and on the stderr if it is 
allowed.


So how do I make stderr not allowed?

In my config, I have the following log related settings in defaults
  log 127.0.0.1:514 daemon
  option httplog

-Patrick



Re: Capturing headers from http/2 trailers?

2019-05-25 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Saturday, May 25, 2019, 01:42 EDT
*To:* Patrick Hemmer 
*Cc:* Haproxy 
*Subject:* Capturing headers from http/2 trailers?


Hi Patrick,

On Fri, May 24, 2019 at 09:00:25AM -0400, Patrick Hemmer wrote:

Is there a way to capture (and log) headers from http/2 response trailers?
The documentation doesn't mention trailers, and when I try to reference
headers which are present in the trailers (e.g. "res.fhdr(grpc-status)"), it
doesn't get captured.

At the end of the day I'm trying to log the grpc-status and grpc-message
headers from gRPC responses.

For now you can't.

Bummer, but thanks for answering.


In fact, in legacy mode, trailers are simply dropped,
and in HTX they're currently encoded in H1 format. Some work has begun
to encode them the same way as regular headers, hoping that in a near
future they can have a more official existence. In this case we could
imagine adding a new analyser which passes after the data forwarding
ones to deal with those, and possibly capture them. Depending on the
complexity this represents we may even possibly imagine backporting
this to 2.0 (e.g. if it's just one analyser triggered in this case).

Based on your experience with gRPC, do you think it would be better to
have different sample fetch functions to look up trailers or to use the
same as the header ones ? My reading of the gRPC spec told me that the
header fields could appear either in headers or trailers sections, which
tends to make me think a unified set would be desirable. But there may
be very valid reasons for prefering to separate them.
The H2 RFC says trailers should be handled as described in RFC7230 
chunked trailers section, which goes on to say:
> When a chunked message containing a non-empty trailer is received, 
the recipient may process the fields (aside from those forbidden above) 
as if they were appended to the message's header section.


So this seems like treating them as one set is acceptable. And with this 
in mind, any producer of headers/trailers must be prepared for the 
consumer to treat them this way.


And yes, from my experience on gRPC, the grpc-status & grpc-message 
headers can appear in both (they appear in headers when there is no 
body). But these 2 headers have a set purpose and meaning. It doesn't 
matter which section the header/value came from, it still means the same 
thing.



Thanks


Re: Capturing headers from http/2 trailers?

2019-05-24 Thread Patrick Hemmer




*From:* Aleksandar Lazic [mailto:al-mob...@none.at]
*Sent:* Friday, May 24, 2019, 20:30 EDT
*To:* Patrick Hemmer 
*Cc:* Haproxy 
*Subject:* Capturing headers from http/2 trailers?


Hi.

Fri May 24 15:00:55 GMT+02:00 2019 Patrick Hemmer :


Is there a way to capture (and log) headers from http/2 response

  > trailers? The documentation doesn't mention trailers, and when I try to
  > reference headers which are present in the trailers (e.g.
  > "res.fhdr(grpc-status)"), it doesn't get captured.
  >
  > At the end of the day I'm trying to log the grpc-status and grpc-message
  > headers from gRPC responses.

In the upcoming 2.0 is ungrpc an protobuf available.

http://git.haproxy.org/?p=haproxy.git;a=blob;f=doc/configuration.txt;h=40424073e58048100f79d08963e49d614a6e7dcb;hb=HEAD

Maybe this will do what you want

The `grpc-status` and `grpc-message` headers are passed as h2 trailers. 
They're not in the protobuf body.


-Patrick


Capturing headers from http/2 trailers?

2019-05-24 Thread Patrick Hemmer
Is there a way to capture (and log) headers from http/2 response 
trailers? The documentation doesn't mention trailers, and when I try to 
reference headers which are present in the trailers (e.g. 
"res.fhdr(grpc-status)"), it doesn't get captured.


At the end of the day I'm trying to log the grpc-status and grpc-message 
headers from gRPC responses.


Thanks

-Patrick



haproxy 1.9.6 segfault in srv_update_status

2019-05-14 Thread Patrick Hemmer
 change_dir = 
    px = 
    pcf = 
#6  0x7f6ea09e41a7 in main (argc=13, argv=0x7ffc51189488) at 
src/haproxy.c:2774

    err = 
    retry = 
    limit = {rlim_cur = 131072, rlim_max = 131072}
    errmsg = 
"\000@\000\000\000\000\000\000\002v\037\237n\177\000\000\300t\004\241n\177\000\000`\027S\237n\177\000\000\030\000\000\000\000\000\000\000>\001\000\024\000\000\000\000p\244\005\241n\177\000\000@\276\001\241n\177\000\000\000P\273\240n\177\000\000\274o\037\237n\177\000\000\370\224\030Q\374\177\000\000\000\000\000\000\000\000\000\000Pw\004\241"

    pidfd = -1

-Patrick



Re: HAProxy 1.9.6 unresponsive

2019-05-13 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Saturday, May 11, 2019, 06:10 EDT
*To:* Patrick Hemmer 
*Cc:* haproxy@formilux.org
*Subject:* HAProxy 1.9.6 unresponsive


Hi Patrick,

On Fri, May 10, 2019 at 09:17:25AM -0400, Patrick Hemmer wrote:

So I see a few updates on some of the other 100% CPU usage threads, and that
some fixes have been pushed. Are any of those in relation to this issue? Or
is this one still outstanding?

Apparently we've pulled a long piece of string and uncovered a series of
such bugs. It's likely that different persons have been affected by
different bugs. We still have the issue Maciej is experiencing that I'd
really like to nail down, given the last occurrence doesn't seem to make
sense as the code looks right after Olivier's fix.

Thanks,
Willy


Thanks, but I'm unsure if that means the issue I reported is fixed, or 
if other related issues are fixed and this one is still outstanding.
There's been mention of releasing 1.9.8. Will that release contain a fix 
for the issue reported in this thread?


-Patrick


Re: HAProxy 1.9.6 unresponsive

2019-05-10 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Tuesday, May 7, 2019, 14:46 EDT
*To:* Patrick Hemmer 
*Cc:* haproxy@formilux.org
*Subject:* HAProxy 1.9.6 unresponsive


Hi Patrick,

On Tue, May 07, 2019 at 02:01:33PM -0400, Patrick Hemmer wrote:

Just in case it's useful, we had the issue recur today. However I gleaned a
little more information from this recurrence. Provided below are several
outputs from a gdb `bt full`. The important bit is that in the captures, the
last frame which doesn't change between each capture is the `si_cs_send`
function. The last stack capture provided has the shortest stack depth of
all the captures, and is inside `h2_snd_buf`.

Thank you. At first glance this remains similar. Christopher and I have
been studying these issues intensely these days because they have deep
roots into some design choices and tradeoffs we've had to make and that
we're relying on, and we've come to conclusions about some long term
changes to address the causes, and some fixes for 1.9 that now appear
valid. We're still carefully reviewing our changes before pushing them.
Then I think we'll emit 1.9.8 anyway since it will already fix quite a
number of issues addressed since 1.9.7, so for you it will probably be
easier to try again.
  
So I see a few updates on some of the other 100% CPU usage threads, and 
that some fixes have been pushed. Are any of those in relation to this 
issue? Or is this one still outstanding?


Thanks

-Patrick



systemd watchdog support?

2019-05-07 Thread Patrick Hemmer
So with the prevalence of the issues lately where haproxy is going 
unresponsive and consuming 100% CPU, I wanted to see what thoughts were 
on implementing systemd watchdog functionality.


In our case, haproxy going unresponsive is extremely problematic as our 
clustering software (pacemaker+systemd) sees the service still running, 
and doesn't realize it needs to restart the service or fail over.
We could look into implementing some sort of custom check resource in 
pacemaker, but before going down that route I wanted to explore the 
systemd watchdog functionality.



The watchdog is implemented by periodically sending "WATCHDOG=1" on the 
systemd notification socket. However there are a few different ways I 
can see this being implemented.


We could put this in the master control process, but this only tells us 
if the master is functioning, not the workers, which are what really matter.


So the next thought would be for all of the workers to listen on a 
shared socket. The master would periodically send a request to that 
socket, and as long as it gets a response, it pings the watchdog. This 
tells us that there is at least one worker able to accept traffic.


However if a frontend is bound to a specific worker, then that would 
frontend would be non-responsive, and the watchdog wouldn't restart the 
service. For that the worker would have to send a request to each worker 
separately, and require a response from all of them before it pings the 
watchdog. This would be better able to detect issues, but for some 
people who aren't using any bound-to-process frontends, they would be 
able to handle failure of a single worker and potentially schedule a 
restart/reload at a less impactful time.


The last idea would be to have the watchdog watch the master only, and 
the master watches the workers in turn. If a worker stops responding, 
the master would restart just that one worker.



Any thoughts on the matter, or do we not want to do this, and rely on a 
custom check in the cluster management software?


-Patrick



Re: HAProxy 1.9.6 unresponsive

2019-05-07 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Monday, May 6, 2019, 08:42 EDT
*To:* Patrick Hemmer 
*Cc:* haproxy@formilux.org
*Subject:* HAProxy 1.9.6 unresponsive


On Sun, May 05, 2019 at 09:40:02AM +0200, Willy Tarreau wrote:

With this said, after studying the code a little bit more, I'm seeing a
potential case where if we'd have a trailers entry in the HTX buffer but
no end of message, we could loop forever there not consuming this block.
I have no idea if this is possible in an HTX message, I'll ask Christopher
tomorrow. In any case we need to address this one way or another, possibly
reporting an error instead if required. Thus I'm postponing 1.9.8 for
tomorrow.

So the case is indeed possible and at the moment all we can do is try to
minimize the probability to produce it :-(  The issue is caused by the
moment we've received the end of trailsers but not the end of the mesage.
 From the H2 protocol perspective if we've sent the END_STREAM flag, the
stream is closed, and a closed stream gets detached and cannot receive
new traffic, so at best we'll occasionally close too early and report
client failures at the upper layers while everything went OK. We cannot
send trailers without the END_STREAM flag since no frame may follow.
Abusing CONTINUATION is out of question here as this would require to
completely freeze the whole connection (including control frames) for
the time it takes to get this final EOM block. I thought about simply
reporting an error when we're in this situation between trailers and EOM
but it will mean that occasionally some chunked responses of sizes close
to 16N kB with trailers may err out, which is not acceptable either.

For 2.0 we approximately see what needs to be modified to address this
situation, but that will not be trivial and not backportable.

For 1.9 I'm still trying to figure what the "best" solution is. I may
finally end up marking the stream as closed as soon as we see the
trailers pushed down. I'm just unsure right now about all the possible
consequences and need to study the edge cases. Also I fear that this
will be something hard to unroll later, so I'm still studying.

Willy


Just in case it's useful, we had the issue recur today. However I 
gleaned a little more information from this recurrence. Provided below 
are several outputs from a gdb `bt full`. The important bit is that in 
the captures, the last frame which doesn't change between each capture 
is the `si_cs_send` function. The last stack capture provided has the 
shortest stack depth of all the captures, and is inside `h2_snd_buf`.


Otherwise it's still the behavior is the same as last time with `strace` 
showing absolutely nothing, so it's still looping.





#0  h1_headers_to_hdr_list (start=0x7f5a4ea6b5fb "grpco\243?", 
stop=0x7f5a4ea6b5ff "o\243?", hdr=hdr@entry=0x7ffdc58f6400, 
hdr_num=hdr_num@entry=101, h1m=h1m@entry=0x7ffdc58f63d0, 
slp=slp@entry=0x0) at src/h1.c:793

    ret = 
    state = 
    ptr = 
    end = 
    hdr_count = 
    skip = 0
    sol = 
    col = 
    eol = 
    sov = 
    sl = 
    skip_update = 
    restarting = 
    n = 
    v = {ptr = 0x7f5a4eb51453 "LZ\177", len = 140025825685243}
#1  0x7f5a4d862539 in h2s_htx_make_trailers 
(h2s=h2s@entry=0x7f5a4ecc7860, htx=htx@entry=0x7f5a4ea67630) at 
src/mux_h2.c:4996
    list = {{n = {ptr = 0x0, len = 0}, v = {ptr = 0x0, len = 0}} 
}

    h2c = 0x7f5a4ec56610
    blk = 
    blk_end = 0x0
    outbuf = {size = 140025844274259, area = 0x7f5a4d996efb 
 
"\205\300~\aHc\320H\001SXH\205\355t\026Lc\310E1\300D\211\351L\211⾃", 
data = 16472, head = 140025845781936}
    h1m = {state = H1_MSG_HDR_NAME, flags = 2056, curr_len = 0, 
body_len = 0, next = 4, err_pos = 0, err_state = 1320431563}

    type = 
    ret = 
    hdr = 0
    idx = 5
    start = 
#2  0x7f5a4d866ef5 in h2_snd_buf (cs=0x7f5a4e9a8980, 
buf=0x7f5a4e777d78, count=4, flags=) at src/mux_h2.c:5372

    h2s = 
    orig_count = 
    total = 16291
    ret = 
    htx = 0x7f5a4ea67630
    blk = 
    btype = 
    idx = 
#3  0x7f5a4d8f4be4 in si_cs_send (cs=cs@entry=0x7f5a4e9a8980) at 
src/stream_interface.c:691

    send_flag = 
    conn = 0x7f5a4e86f4c0
    si = 0x7f5a4e777f98
    oc = 0x7f5a4e777d70
    ret = 
    did_send = 0
#4  0x7f5a4d8f6305 in si_cs_io_cb (t=, 
ctx=0x7f5a4e777f98, state=) at src/stream_interface.c:737

    si = 0x7f5a4e777f98
    cs = 0x7f5a4e9a8980
    ret = 0
#5  0x7f5a4d925f02 in process_runnable_tasks () at src/task.c:437
    t = 
    state = 
    ctx = 
    process = 
    t = 
    max_processed = 
#6  0x7f5a4d89f6ff in run_poll_loop () at src/haproxy.c:2642
    next = 
    exp = 
#7  run_thread_poll_loop 

Re: [PATCH v2 1/2] MINOR: systemd: Use the variables from /etc/default/haproxy

2019-05-06 Thread Patrick Hemmer




*From:* Tim Duesterhus [mailto:t...@bastelstu.be]
*Sent:* Monday, May 6, 2019, 07:00 EDT
*To:* haproxy@formilux.org
*Cc:* Apollon Oikonomopoulos , 
wlallem...@haproxy.com, w...@1wt.eu, ber...@debian.org, Tim Duesterhus 

*Subject:* [PATCH v2 1/2] MINOR: systemd: Use the variables from 
/etc/default/haproxy



From: Apollon Oikonomopoulos 

This will allow seamless upgrades from the sysvinit system while respecting
any changes the users may have made. It will also make local configuration
easier than overriding the systemd unit file.

Note by Tim:

This GPL-2 licensed patch was taken from the Debian project at [1].

It was slightly modified to cleanly apply, because HAProxy's default unit
file does not include rsyslog.service as an 'After' dependency. Also the
subject line was modified to include the proper subsystem and severity.

This patch may be backported to 1.9.

[1] 
https://salsa.debian.org/haproxy-team/haproxy/blob/master/debian/patches/haproxy.service-use-environment-variables.patch

Co-authored-by: Tim Duesterhus 
---
  contrib/systemd/haproxy.service.in | 7 ---
  1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/contrib/systemd/haproxy.service.in 
b/contrib/systemd/haproxy.service.in
index 74e66e302..138701223 100644
--- a/contrib/systemd/haproxy.service.in
+++ b/contrib/systemd/haproxy.service.in
@@ -3,10 +3,11 @@ Description=HAProxy Load Balancer
  After=network.target
  
  [Service]

+EnvironmentFile=-/etc/default/haproxy
  Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid"
-ExecStartPre=@SBINDIR@/haproxy -f $CONFIG -c -q
-ExecStart=@SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE
-ExecReload=@SBINDIR@/haproxy -f $CONFIG -c -q
+ExecStartPre=@SBINDIR@/haproxy -f $CONFIG -c -q $EXTRAOPTS
+ExecStart=@SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS
+ExecReload=@SBINDIR@/haproxy -f $CONFIG -c -q $EXTRAOPTS
  ExecReload=/bin/kill -USR2 $MAINPID
  KillMode=mixed
  Restart=always


/etc/default is a debianism. Other distros use different directories, 
such as RedHat which uses /etc/sysconfig


-Patrick


HAProxy 1.9.6 unresponsive

2019-05-03 Thread Patrick Hemmer
 backend servers are h2c 
(no SSL).


The service has been restarted, so it cannot be probed any more. However 
I did capture a core file before doing so.


-Patrick


Re: [PATCH] MINOR: systemd: Make use of master socket in systemd unit

2019-04-30 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Monday, April 29, 2019, 23:55 EDT
*To:* William Lallemand 
*Cc:* Tim Düsterhus , Patrick Hemmer 
, haproxy@formilux.org

*Subject:* [PATCH] MINOR: systemd: Make use of master socket in systemd unit


On Tue, Apr 30, 2019 at 01:47:13AM +0200, William Lallemand wrote:

the systemd API
is limited and it's not possible to report a fail during a reload with 
sd_notify.

Anyway a service manager which requires daemons to stay in foreground,
does not allow processes to be replaced, and relies on asynchronous and
unidirectional signal delivery to perform critical actions such as config
updates is obviously misdesigned and can only result from the lack of
experience of production servers and people making them work every day.

I tend to think that the only longterm solution to work around all the
systemd imposed mess is to have haproxy become its own service manager.
It is a shame as it significantly complicates haproxy management on Linux
compared to sane operating systems, but I'm having a hard time accepting
that haproxy has become less reliable on Linux due to systemd. We've
already made progress in this direction with the master-worker model,
but we need to go further and make haproxy be able to serve as a client
to talk to an existing master and return relevant status codes. This
way we'll be able to emulate the start/reload/restart operations that
are performed on sane systems and gain reliability again, at the
expense of using a total of 3 processes talking to each other during
a reload instead of just one. The advantage is that it should work on
other operating systems too if needed.

In my opinion this is something we seriously need to work on for 2.1,
and address remaining limitations (doubled memory usage and CLI being
closed on reload).

By the way, does systemd support passing actions on stdin and getting
the result on stdout ? Given that the master process is forced to
stay in foreground, at least we could have the equivalent of the CLI
on stdio used as a "console" and not require a third process to talk
to it.

Willy
Not to start a systemd flame war, but you can always tell systemd to 
stop tracking the process, and you can then do whatever you want. Of 
course you won't get automatic restarts if it dies, but that's how all 
the other "sane operating systems" behave.

Just add to the service file:
Type=oneshot
RemainAfterExit=yes

Assuming we don't do that, and going back to the original issue at hand 
of putting the master socket in the systemd unit: do we want to do this? 
From all the discussion, whether or not we add a `haproxy reload` 
command to the haproxy binary, it still seems like we will need master 
socket support to make it work. So should this patch be adopted?


-Patrick



Re: [PATCH] MINOR: systemd: Make use of master socket in systemd unit

2019-04-29 Thread Patrick Hemmer




*From:* Tim Düsterhus [mailto:t...@bastelstu.be]
*Sent:* Friday, April 26, 2019, 15:03 EDT
*To:* Patrick Hemmer , William Lallemand 


*Cc:* haproxy@formilux.org, w...@1wt.eu
*Subject:* [PATCH] MINOR: systemd: Make use of master socket in systemd unit


Patrick,

Am 26.04.19 um 20:55 schrieb Patrick Hemmer:

One other consideration is a problem I've been looking to address, and
that's better reloads. Right now the systemd unit sends a signal for the
reload, but sending a signal gets no feedback on whether the reload
operation was successful or not.

Have you checked that you are using Type=notify in your unit file? It
uses systemd's sd_notify API to communicate the reload to systemd which
should do what you are searching for.

See this mailing list thread:
https://www.mail-archive.com/haproxy@formilux.org/msg27874.html

Best regards
Tim Düsterhus


Yes, we use Type=notify. The problem though is that systemd is reporting 
reload success even if the reload fails.


Take the following example config:

global
stats socket /tmp/foo

With the current systemd file provided by haproxy, I copied it as 
"haproxy-test.service" and modified one line to the following:


Environment="CONFIG=/tmp/haproxy.cfg" "PIDFILE=/run/haproxy-test.pid"

And started haproxy:

# systemctl start haproxy-test.service
-- Logs begin at Thu 2019-04-11 15:13:39 EDT. --
Apr 29 14:24:14 fll2albs01qa2 systemd[1]: Starting HAProxy Load Balancer...
Apr 29 14:24:14 fll2albs01qa2 haproxy[27702]: [NOTICE] 118/142414 
(27702) : New worker #1 (27704) forked

Apr 29 14:24:14 fll2albs01qa2 systemd[1]: Started HAProxy Load Balancer.

I then edited the config and changed the stats socket line to:

stats socket /notmp/foo

And then tried a reload:
# systemctl reload haproxy-test.service
-- Logs begin at Thu 2019-04-11 15:13:39 EDT. --
Apr 29 14:24:47 fll2albs01qa2 haproxy[27702]: [WARNING] 118/142447 
(27702) : Reexecuting Master process
Apr 29 14:24:47 fll2albs01qa2 haproxy[27702]: [ALERT] 118/142447 (27702) 
: Starting frontend GLOBAL: cannot bind UNIX socket [/notmp/foo]
Apr 29 14:24:47 fll2albs01qa2 haproxy[27702]: [WARNING] 118/142447 
(27702) : Reexecuting Master process in waitpid mode
Apr 29 14:24:47 fll2albs01qa2 haproxy[27702]: [WARNING] 118/142447 
(27702) : Reexecuting Master process

Apr 29 14:24:47 fll2albs01qa2 systemd[1]: Reloaded HAProxy Load Balancer.

# systemctl status haproxy-test.service
● haproxy-test.service - HAProxy Load Balancer
   Loaded: loaded (/etc/systemd/system/haproxy-test.service; disabled; 
vendor preset: disabled)

   Active: active (running) since Mon 2019-04-29 14:24:14 EDT; 45s ago
  Process: 28335 ExecReload=/bin/kill -USR2 $MAINPID (code=exited, 
status=0/SUCCESS)
  Process: 28334 ExecReload=/usr/sbin/haproxy -f $CONFIG -c -q 
(code=exited, status=0/SUCCESS)
  Process: 27700 ExecStartPre=/usr/sbin/haproxy -f $CONFIG -c -q 
(code=exited, status=0/SUCCESS)

 Main PID: 27702 (haproxy)
   Memory: 2.9M
   CGroup: /system.slice/haproxy-test.service
   ├─27702 /usr/sbin/haproxy -Ws -f /tmp/haproxy.cfg -p 
/run/haproxy-test.pid -sf 27704
   └─27704 /usr/sbin/haproxy -Ws -f /tmp/haproxy.cfg -p 
/run/haproxy-test.pid


Note that the reload failed, but systemd reports success.

With older versions of haproxy (<1.8) we had a script which checked the 
PID of the master process and that it changed after sending SIGUSR2. 
This strategy no longer works.


Re: [PATCH] MINOR: systemd: Make use of master socket in systemd unit

2019-04-26 Thread Patrick Hemmer




*From:* Tim Düsterhus [mailto:t...@bastelstu.be]
*Sent:* Friday, April 26, 2019, 14:30 EDT
*To:* William Lallemand 
*Cc:* haproxy@formilux.org, w...@1wt.eu
*Subject:* [PATCH] MINOR: systemd: Make use of master socket in systemd unit


William,

Am 26.04.19 um 14:56 schrieb William Lallemand:

On Fri, Apr 26, 2019 at 12:15:37AM +0200, Tim Duesterhus wrote:

  [Service]
-Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid"
+Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" 
"MASTER_SOCKET=/run/haproxy-master.sock"
  ExecStartPre=@SBINDIR@/haproxy -f $CONFIG -c -q
-ExecStart=@SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE
+ExecStart=@SBINDIR@/haproxy -Ws -S $MASTER_SOCKET -f $CONFIG -p $PIDFILE
  ExecReload=@SBINDIR@/haproxy -f $CONFIG -c -q

In my opinion that's not a good idea to do it this way, because you can't
disable the master CLI by unsetting the MASTER_SOCKET variable.

It's probably better to have "-S /run/haproxy-master.sock" in an $OPTIONS
variable at the end of the ExecStart line.


I'm not sure whether this is better. Yes you can disable the socket more
easily then, but you have to remember to add it back when editing the
'OPTIONS' variable.

I believe it boils to to this question: Does the user usually want to
run with the socket enabled or not? My guess is that most users want to
have this socket (having is better than needing!), they might just want
to move it to a different location rather than outright disabling it.
During my tests it was only accessible to root, so there does not appear
a security issue in the default configuration either.

On an unrelated note: Debian patches the unit file to add in such a
variable, called 'EXTRAOPTS':
https://salsa.debian.org/haproxy-team/haproxy/blob/master/debian/patches/haproxy.service-use-environment-variables.patch

So if we want to go the 'OPTIONS' variable path we might want to re-use
that variable name. Any change will break their patch anyway so they
definitely notice.

Best regards
Tim Düsterhus

One other consideration is a problem I've been looking to address, and 
that's better reloads. Right now the systemd unit sends a signal for the 
reload, but sending a signal gets no feedback on whether the reload 
operation was successful or not.


I haven't thought about this a whole lot, but I'm thinking the way to 
address it would be some sort of inquiry to the master process, which 
means using the socket. So if the systemd unit file ensured that the 
master socket is available, then ExecReload could be adjusted to use it 
and get success/failure feedback.


-Patrick


Re: `stats bind-process` broken

2019-04-11 Thread Patrick Hemmer




*From:* Willy Tarreau [mailto:w...@1wt.eu]
*Sent:* Thursday, April 11, 2019, 13:23 EDT
*To:* Patrick Hemmer 
*Cc:* haproxy@formilux.org, wlallem...@haproxy.com
*Subject:* `stats bind-process` broken


On Thu, Apr 11, 2019 at 06:51:59PM +0200, Willy Tarreau wrote:

I'm leaning towards what I'd consider a cleaner and more future-proof
option consisting in deprecating "stats bind-process" in favor of "process"
on the stats line (which binds the listener itself, not the whole frontend)
and emitting a warning at startup time if master-worker + this option are
set together, explaining what to do instead. I think it could be a reasonably
acceptable change for 1.9/2.0 given that the overlap between master-worker
and "stats bind-process" should not be high.

Would you see any issue with this if the warning gives all the indications
on what to do ?

So just to let you know that after discussing this with William, we might
have another solution consisting in moving the master-worker socketpair
to a dedicated frontend instead. It looks more future-proof but we need
to validate a number of points before engaging that route.

Regards,
Willy
In regards to deprecating `stats bind-process`, I think this would be 
acceptable. I can't think of any issues that might arise from that. 
Though I'm not sure what else is part of this frontend, which I'm 
gathering is some sort of hidden frontend used for the stats socket, 
master-worker communication, and may be other things.

Seems like `stats socket ... process` would indeed be safer in that regard.

-Patrick


`stats bind-process` broken

2019-04-11 Thread Patrick Hemmer
With haproxy 1.9.6 the `stats bind-process` directive is not working. 
Every connection to the socket is going to a random process:


Here's a simple reproduction:
Config:
   global
       nbproc 3
       stats socket /tmp/haproxy.sock level admin
       stats bind-process 1


Testing:
   # for i in {1..5}; do socat - unix:/tmp/haproxy.sock <<< "show info" 
| grep Pid: ; done

   Pid: 33371
   Pid: 33373
   Pid: 33372
   Pid: 33373
   Pid: 33373

-Patrick


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-04 Thread Overbey, Patrick (Sioux Falls)
That worked great. Thanks Willy!

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Wednesday, April 03, 2019 10:01 PM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




On Wed, Apr 03, 2019 at 09:49:34PM +, Overbey, Patrick (Sioux Falls) wrote:
> Actually, here is the error. The warning was just the last thing that printed 
> to the screen.
>
> In file included from /usr/include/netinet/tcp.h:113,
>  from include/common/compat.h:32,
>  from src/connection.c:15:
> src/connection.c: In function 'conn_recv_netscaler_cip':
> src/connection.c:792:10: error: expected '=', ',', ';', 'asm' or 
> '__attribute__' before '.' token
>   uint8_t ip_v;
>   ^~~~
> src/connection.c:792:10: error: expected expression before '.' token
> src/connection.c:860:2: error: 'ip_ff' undeclared (first use in this 
> function); did you mean 'ip_fv'?
>   ip_v = (*line & 0xf0) >> 4;

Ah so I forgot to backport a few AIX-specific patches! And I'm seeing that I 
somewhat messed up with the unsetenv fix as the define on the command line was 
included as part of a previous one. I'm sorry, that's fixed now. Let's try 
again :-)

Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-03 Thread Overbey, Patrick (Sioux Falls)
Actually, here is the error. The warning was just the last thing that printed 
to the screen.

In file included from /usr/include/netinet/tcp.h:113,
 from include/common/compat.h:32,
 from src/connection.c:15:
src/connection.c: In function 'conn_recv_netscaler_cip':
src/connection.c:792:10: error: expected '=', ',', ';', 'asm' or 
'__attribute__' before '.' token
  uint8_t ip_v;
  ^~~~
src/connection.c:792:10: error: expected expression before '.' token
src/connection.c:860:2: error: 'ip_ff' undeclared (first use in this function); 
did you mean 'ip_fv'?
  ip_v = (*line & 0xf0) >> 4;
  ^~~~

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Wednesday, April 03, 2019 3:50 PM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




On Wed, Apr 03, 2019 at 08:40:35PM +0000, Overbey, Patrick (Sioux Falls) wrote:
> It looks the same to me. Thanks.
>
> In file included from src/connection.c:17:
> src/connection.c: In function '__initcb_1302':
> include/common/initcall.h:128:11: warning: cast between incompatible 
> function ty

At least the line has changed, indicating that the macro correctly made its way 
to the code. I need to scratch my head now.


> pes from 'void (*)(struct sample_fetch_kw_list *)' to 'void (*)(void 
> *, void *, void *)' [-Wcast-function-type]
>.fct  = (void (*)(void *,void *,void *))function,  \
>^
> include/common/initcall.h:146:2: note: in expansion of macro 
> '__DECLARE_INITCALL '
>   __DECLARE_INITCALL(__VA_ARGS__)
>   ^~
> include/common/initcall.h:158:2: note: in expansion of macro 
> '_DECLARE_INITCALL'
>
>   _DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0)
>   ^
> src/connection.c:1302:1: note: in expansion of macro 'INITCALL1'
>  INITCALL1(STG_REGISTER, sample_register_fetches, 
> _fetch_keywords);  ^
> gmake: *** [Makefile:996: src/connection.o] Error 1

Note, I'm only seeing a warning and not the error here. So I don't understand 
why the compilation stopped. And I don't understand why the warning above 
wasn't automatically disabled since the compiler supports it.

Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-03 Thread Overbey, Patrick (Sioux Falls)
It looks the same to me. Thanks.

In file included from src/connection.c:17:
src/connection.c: In function '__initcb_1302':
include/common/initcall.h:128:11: warning: cast between incompatible function ty
pes from 'void (*)(struct sample_fetch_kw_list *)' to 'void (*)(void *, void *,
void *)' [-Wcast-function-type]
   .fct  = (void (*)(void *,void *,void *))function,  \
   ^
include/common/initcall.h:146:2: note: in expansion of macro '__DECLARE_INITCALL
'
  __DECLARE_INITCALL(__VA_ARGS__)
  ^~
include/common/initcall.h:158:2: note: in expansion of macro '_DECLARE_INITCALL'

  _DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0)
  ^
src/connection.c:1302:1: note: in expansion of macro 'INITCALL1'
 INITCALL1(STG_REGISTER, sample_register_fetches, _fetch_keywords);
 ^
gmake: *** [Makefile:996: src/connection.o] Error 1

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Wednesday, April 03, 2019 3:34 PM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




On Wed, Apr 03, 2019 at 08:20:50PM +, Overbey, Patrick (Sioux Falls) wrote:
> Sorry, Willy. I'm still having the same troubles after the changes.

Then there's something I'm missing because it works for me here (with and 
without the option, I verified that I had different symbols in the output), and 
in addition the reported line number in initcall.h (105) belongs to the case 
where USE_OBSOLETE_LINKER is *not* defined.

Could you please double-check and send again the copy of the error you get with 
this latest commit ? It might look similar but be slightly different, 
indicating something else is needed.

Thanks,
Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-03 Thread Overbey, Patrick (Sioux Falls)
Sorry, Willy. I'm still having the same troubles after the changes.

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Wednesday, April 03, 2019 3:10 PM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




Hi Patrick,

On Wed, Apr 03, 2019 at 03:32:23PM +, Overbey, Patrick (Sioux Falls) wrote:
> Hi Willy,
> I brought down haproxy-1.9-1483198 through git, but am getting 
> expansion of macro errors during the compile using the same compile 
> script that works with 2.0. Any ideas what's wrong?
(...)

Oh I know, it's because I'm stupid, but that's fixed now (the bug, not my 
stupidity unfortunately). In 2.0 all the USE_* macros are automatically passed 
to compiler options. In 1.9 we have to explicitly append them in the makefile. 
And guess what I forgot to add ? :-)

It's OK for me with commit 01a2c4 now.

Thanks for reporting this, and sorry for the confusion!
Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-03 Thread Overbey, Patrick (Sioux Falls)
Hi Willy,
I brought down haproxy-1.9-1483198 through git, but am getting expansion of 
macro errors during the compile using the same compile script that works with 
2.0. Any ideas what's wrong?

For example, I ran "gmake -B CFLAGS="-maix64" LDFLAGS="-maix64" TARGET=aix52 
USE_OPENSSL=1 USE_ZLIB=1 2>&1 | tee haproxy-make.log" :

In file included from src/connection.c:17:
include/common/initcall.h:105:10: warning: cast between incompatible function ty
pes from 'void (*)(struct sample_fetch_kw_list *)' to 'void (*)(void *, void *,
void *)' [-Wcast-function-type]
   .fct = (void (*)(void *,void *,void *))function,   \
  ^
include/common/initcall.h:146:2: note: in expansion of macro '__DECLARE_INITCALL
'
  __DECLARE_INITCALL(__VA_ARGS__)
  ^~
include/common/initcall.h:158:2: note: in expansion of macro '_DECLARE_INITCALL'

  _DECLARE_INITCALL(stage, __LINE__, function, arg1, 0, 0)
  ^
src/connection.c:1302:1: note: in expansion of macro 'INITCALL1'
 INITCALL1(STG_REGISTER, sample_register_fetches, _fetch_keywords);
 ^
gmake: *** [Makefile:991: src/connection.o] Error 1


Thanks.

Patrick Overbey
Fiserv


-Original Message-
From: Overbey, Patrick (Sioux Falls) 
Sent: Wednesday, April 03, 2019 7:53 AM
To: Willy Tarreau 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: RE: Upcoming haproxy build fixes for Cygwin & AIX

Great. Thank you Willy.

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Wednesday, April 03, 2019 1:18 AM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




Hi Patrick,

On Mon, Apr 01, 2019 at 09:27:46PM +, Overbey, Patrick (Sioux Falls) wrote:
> Thanks. Can you let me know when the change is ported back to 1.9?

OK so this is now in the 1.9-maint branch (commit 3349375). You can retrieve it 
with git, or if you wait another day you'll get a nightly snapshot in the 
download directory. In absence of pending bugs, I don't think there will be 
another 1.9 release before week.

Regards,
Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-03 Thread Overbey, Patrick (Sioux Falls)
Great. Thank you Willy.

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Wednesday, April 03, 2019 1:18 AM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




Hi Patrick,

On Mon, Apr 01, 2019 at 09:27:46PM +, Overbey, Patrick (Sioux Falls) wrote:
> Thanks. Can you let me know when the change is ported back to 1.9?

OK so this is now in the 1.9-maint branch (commit 3349375). You can retrieve it 
with git, or if you wait another day you'll get a nightly snapshot in the 
download directory. In absence of pending bugs, I don't think there will be 
another 1.9 release before week.

Regards,
Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-01 Thread Overbey, Patrick (Sioux Falls)
Thanks. Can you let me know when the change is ported back to 1.9?

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Monday, April 01, 2019 3:23 PM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




On Mon, Apr 01, 2019 at 07:50:20PM +, Overbey, Patrick (Sioux Falls) wrote:
> Not really necessary since "aix52" works. Production servers should really be 
> AIX 7.1+ anyway.

OK, thanks for the info.

Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-01 Thread Overbey, Patrick (Sioux Falls)
Not really necessary since "aix52" works. Production servers should really be 
AIX 7.1+ anyway.

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Monday, April 01, 2019 2:48 PM
To: Overbey, Patrick (Sioux Falls) 
Cc: maio...@gmail.com; haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




On Mon, Apr 01, 2019 at 07:05:04PM +0000, Overbey, Patrick (Sioux Falls) wrote:
> I was able to compile HA-Proxy version 2.0-dev2-ce4ec50 2019/04/01 with these 
> options using an AIX 6.1.9 system and openssl 1.0.2q. Thank you!
>
> gmake CFLAGS="-maix64" LDFLAGS="-maix64" TARGET=aix52 USE_OPENSSL=1 
> USE_PCRE=1 USE_ZLIB=1

Excellent! Do you want me to add an "aix61" target with these flags, as I guess 
all AIX 6 will require -maix64 anyway ?

Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-04-01 Thread Overbey, Patrick (Sioux Falls)
I was able to compile HA-Proxy version 2.0-dev2-ce4ec50 2019/04/01 with these 
options using an AIX 6.1.9 system and openssl 1.0.2q. Thank you!

gmake CFLAGS="-maix64" LDFLAGS="-maix64" TARGET=aix52 USE_OPENSSL=1 USE_PCRE=1 
USE_ZLIB=1

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Monday, April 01, 2019 2:06 AM
To: maio...@gmail.com; Overbey, Patrick (Sioux Falls) 

Cc: haproxy@formilux.org
Subject: Re: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




On Mon, Apr 01, 2019 at 09:04:06AM +0800, ??? wrote:
> Many thanks Willy, I will wait and to try and study your patch.

You're welcome.

So I've just pushed the latest fixes to the master branch.
What I've done is the following :

  - enabled the new USE_OBSOLETE_LINKER option on both flavors of AIX
and on cygwin by default since we know the linker doesn't provide
our section start/end pointers there ;

  - enabled USE_PRIVATE_CACHE on aix51 because it complained about
missing symbols like __sync_sub_and_fetch_4. If on more recent
AIX or on Cygwin you experience this, you'll have to add
USE_PRIVATE_CACHE=1 as well (then let me know so that I can update
the default build options)

  - added a few defines on the CFLAGS to build on aix51 :
  -Dss_family=__ss_family -Dip6_hdr=ip6hdr -DSTEVENS_API \
  -D_LINUX_SOURCE_COMPAT -Dunsetenv=my_unsetenv
=> you may or may not need some of them on a more recent AIX version.
   On cygwin, maybe unsetenv will be needed, I don't know.

You need to have at least commit 13d9b023 in your repository for this to be 
available. Once we figure all the required options for you to get this version 
to build, I'll backport them to 1.9.

I managed to build this version with openssl 1.0.2 support on a very old 
Power3/333 MHz running AIX 5.1 and to run an H2 test. This sounds a bit like an 
anachronism though :-)

Cheers,
Willy


RE: Upcoming haproxy build fixes for Cygwin & AIX

2019-03-29 Thread Overbey, Patrick (Sioux Falls)
Wow. Really appreciate you following up. Thanks Willy!

Patrick Overbey
Fiserv

-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Friday, March 29, 2019 4:01 PM
To: maio...@gmail.com; Overbey, Patrick (Sioux Falls) 

Cc: haproxy@formilux.org
Subject: Upcoming haproxy build fixes for Cygwin & AIX

  ⚠ EXTERNAL MESSAGE – Think Before You Click




Hi,

I finally could figure how to work around the issues with very old linkers. I 
could work on this using a very old AIX machine we have here running AIX 5.1, 
so now that my test code works on it, I'm fairly confident more recent versions 
will as well, and given that Jeffrey's errors on Cygwin where the same, I think 
it's all that's missing there as well.

I'll clean up my patches this week-end or on Monday and will ask you to give 
them a try. I'll merge them into 2.0 to make it easier for you to test, and 
will backport them to 1.9 once you confirm the issue is gone for you as well.

I suspect Solaris versions older than 10 will need the same workaround as well, 
but it will only be a matter of adding a build option, which will be easy. I 
can't test there, my old Ultra5 is really sick...

So stay tuned!
Willy


Re: Adding Configuration parts via File

2019-03-08 Thread Patrick Hemmer


On 2019/3/8 08:17, Philipp Kolmann wrote:
> Hi,
>
> I have ACLs for Source-IPs for Admins for several services. These ACLs
> are identical for multiple listener-sections.
>
> Would it be possible to have a file with several acl snipplets and
> source that at the proper section of the config file multiple times?
> I haven't found anything in the docs that would make this possible.
>
> My wished Setup:
>
> admin_acl.conf:
>
> acl is_admin src 10.0.0.1
> acl is_admin src 10.0.0.2
> acl is_admin src 10.0.0.3
> acl is_admin src 10.0.0.4
>
>
> haproxy.cfg:
>
> listen service1
> bind 10.1.0.10:80
> include admin_acl.conf
>
>  more parameters ...
>
>
> listen service2
> bind 10.1.0.20:80
> include admin_acl.conf
>
>  more parameters ...
>
>
> listen service3
> bind 10.1.0.30:80
> include admin_acl.conf
>
>  more parameters ...
>
>
> The admin_acl needs to be maintained only once and can be used
> multiple times.
>
> Is this already possible? Could such an include option be made for the
> config files?
>
> thanks
> Philipp
>

You can use external files in two cases. See the following blog articles:

https://www.haproxy.com/blog/introduction-to-haproxy-acls/ (search for
"acl file")

https://www.haproxy.com/blog/introduction-to-haproxy-maps/

-Patrick



Re: Issue with systemd haproxy.service on RHEL 7.4

2019-03-07 Thread Patrick Hemmer


On 2019/3/7 11:08, Badari Prasad wrote:
> Hi  
>  RHEL 7.4 comes with haproxy 1.5.18, I wanted use latest version of
> haproxy 1.9.4.  So source code comes with haproxy.service.in
> <http://haproxy.service.in>
> [https://github.com/haproxy/haproxy/blob/master/contrib/systemd/haproxy.service.in]
> .
> Executing make in the dir contrib/systemd/ creates haproxy.service. I
> tried to copy this generarted file in
> : /usr/lib/systemd/system/haproxy.service .
> With this I see lots of errors : 
> #systemctl status haproxy.service
> ● haproxy.service - HAProxy Load Balancer
>Loaded: loaded (/usr/lib/systemd/system/haproxy.service; disabled;
> vendor preset: disabled)
>Active: inactive (dead)
>
> Mar 07 03:13:47 local systemd[1]:
> [/usr/lib/systemd/system/haproxy.service:9] Executable path is not
> absolute, ignoring: @SBINDIR@/haproxy -f $CONFIG -c -q
> Mar 07 03:13:47 local systemd[1]: haproxy.service lacks both
> ExecStart= and ExecStop= setting. Refusing.
> Mar 07 03:13:47 local systemd[1]:
> [/usr/lib/systemd/system/haproxy.service:3] Failed to add dependency
> on =syslog.target, ignoring: Invalid argument
> Mar 07 03:13:47 local systemd[1]:
> [/usr/lib/systemd/system/haproxy.service:7] Executable path is not
> absolute, ignoring: @SBINDIR@/haproxy -f $CONFIG -c -q
> Mar 07 03:13:47 local systemd[1]:
> [/usr/lib/systemd/system/haproxy.service:8] Executable path is not
> absolute, ignoring: @SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE
> Mar 07 03:13:47 local systemd[1]:
> [/usr/lib/systemd/system/haproxy.service:9] Executable path is not
> absolute, ignoring: @SBINDIR@/haproxy -f $CONFIG -c -q
> Mar 07 03:13:47 local systemd[1]: haproxy.service lacks both
> ExecStart= and ExecStop= setting. Refusing.
> Mar 07 03:29:51 local systemd[1]: Unit haproxy.service cannot be
> reloaded because it is inactive.
> Mar 07 09:28:57 local systemd[1]: Unit haproxy.service cannot be
> reloaded because it is inactive.
> Mar 07 09:35:45 local systemd[1]: Unit haproxy.service cannot be
> reloaded because it is inactive.
>
>
> Have attached haproxy.service for reference. Can I get some pointers
> to resolve this issue.
>
> Thanks
>  badari 
>
>

Differences between the output you have provided and the attached
service file indicates that you had an earlier version of the service
file present on your system, and have not reloaded systemd since
modifying it, so it's using the old file.
You need to run: `systemctl daemon-reload`

-Patrick


http/2 server-push support

2019-02-26 Thread Patrick Hemmer
Now that we have h2 support on frontends, backends, trailers, etc, I'm
hoping that server side server-push is somewhere on the roadmap. By
"server side" I mean not this middleware based server-push methodology
frequently used where a "Link" header is converted to a server push. But
instead where the server itself can generate the server-push responses.

Is there any plan on this, or when it might be available?

If it helps for prioritization, our use case for this is reduce
processing overhead. A single request might require the client to have
related resources, and those related resources might all involve
computation that is shared. If each request is handled separately (e.g.
Link header to server-push conversion), it would result in a lot of
duplicated work. So instead we want to do the computation once, and push
out the multiple responses separately.

-Patrick


Re: Error parsing commas in str() fetch

2019-02-23 Thread Patrick Hemmer


On 2019/2/23 18:18, Nick Ramirez wrote:
>
> If I set a variable like this:
>
>
> /http-request set-var(txn.allowed_methods) str("GET,POST,PUT")/
>
>
> Then I get an error:
>
>
> /parsing [/etc/haproxy/haproxy.cfg:20] : error detected in frontend
> 'fe_proxy' while parsing 'http-request set-var(txn.allowed_methods)'
> rule : fetch method 'str' : end of arguments expected at position 2,
> but got ',POST,PUT,OPTIONS'./
>
>
> This seems like HAProxy is parsing the comma as a delimiter between
> arguments to the str() fetch method instead of including it as part of
> the string that's surrounded by double quotes. Is this expected
> behavior? If so, is there a work-around? Some way to escape commas in
> a string passed to str()?
>
>
> Nick Ramirez
>

Yes this is known behavior. In the config documentation, on some of the
keywords, you'll see:
> Note that due to the config parser, it is not possible to use a comma
nor a closing parenthesis as delimitors.

You can get around it by using converters, and some sort of encoded
text, such as URL or base64. For example:

str(GET%2CPOST%2CPUT),url_dec()


-Patrick


Re: Compilation fails on OS-X

2019-02-14 Thread Patrick Hemmer


On 2019/2/14 12:45, Olivier Houchard wrote:
> Hi Patrick,
>
> On Thu, Feb 14, 2019 at 09:12:18AM -0500, Patrick Hemmer wrote:
>>
>> On 2019/2/14 08:20, Frederic Lecaille wrote:
>>> On 2/14/19 1:32 PM, Frederic Lecaille wrote:
>>>> On 2/13/19 7:30 PM, Patrick Hemmer wrote:
>>>>>
>>>>> On 2019/2/13 10:29, Olivier Houchard wrote:
>>>>>> Hi Patrick,
>>>>>>
>>>>>> On Wed, Feb 13, 2019 at 10:01:01AM -0500, Patrick Hemmer wrote:
>>>>>>> On 2019/2/13 09:40, Aleksandar Lazic wrote:
>>>>>>>> Am 13.02.2019 um 14:45 schrieb Patrick Hemmer:
>>>>>>>>> Trying to compile haproxy on my local machine for testing
>>>>>>>>> purposes and am
>>>>>>>>> running into the following:
>>>>>>>> Which compiler do you use?
>>>>>>> # gcc -v
>>>>>>> Configured with:
>>>>>>> --prefix=/Applications/Xcode.app/Contents/Developer/usr
>>>>>>> --with-gxx-include-dir=/usr/include/c++/4.2.1
>>>>>>> Apple LLVM version 9.0.0 (clang-900.0.39.2)
>>>>>>> Target: x86_64-apple-darwin17.7.0
>>>>>>> Thread model: posix
>>>>>>> InstalledDir:
>>>>>>> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
>>>>>>>
>>>>>>>
>>>>>>>>>  # make TARGET=osx
>>>>>>>>>  src/proto_http.c:293:1: error: argument to 'section'
>>>>>>>>> attribute is not
>>>>>>>>> valid for this target: mach-o section specifier requires a
>>>>>>>>> segment and section
>>>>>>>>> separated by a comma
>>>>>>>>>  DECLARE_POOL(pool_head_http_txn, "http_txn",
>>>>>>>>> sizeof(struct http_txn));
>>>>>>>>>  ^
>>>>>>>>>  include/common/memory.h:128:2: note: expanded from
>>>>>>>>> macro 'DECLARE_POOL'
>>>>>>>>>  REGISTER_POOL(, name, size)
>>>>>>>>>  ^
>>>>>>>>>  include/common/memory.h:123:2: note: expanded from
>>>>>>>>> macro 'REGISTER_POOL'
>>>>>>>>>  INITCALL3(STG_POOL,
>>>>>>>>> create_pool_callback, (ptr), (name),
>>>>>>>>> (size))
>>>>>>>>>  ^
>>>>>>>>>  include/common/initcall.h:102:2: note: expanded from
>>>>>>>>> macro 'INITCALL3'
>>>>>>>>>  _DECLARE_INITCALL(stage, __LINE__,
>>>>>>>>> function, arg1, arg2,
>>>>>>>>> arg3)
>>>>>>>>>  ^
>>>>>>>>>  include/common/initcall.h:78:2: note: expanded from macro
>>>>>>>>> '_DECLARE_INITCALL'
>>>>>>>>>  __DECLARE_INITCALL(__VA_ARGS__)
>>>>>>>>>  ^
>>>>>>>>>  include/common/initcall.h:65:42: note: expanded from macro
>>>>>>>>> '__DECLARE_INITCALL'
>>>>>>>>> __attribute__((__used__,__section__("init_"#stg))) =   \
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Issue occurs on master, and the 1.9 branch
>>>>>>>>>
>>>>>>>>> -Patrick
>>>>>> Does the (totally untested, because I have no Mac to test) patch
>>>>>> works for
>>>>>> you ?
>>>>> Unfortunately not. Just introduces a lot of new errors:
>>>>>
>>>>>
>>>>>  In file included from src/ev_poll.c:22:
>>>>>  In file included from include/common/hathreads.h:26:
>>>>>  include/common/initcall.h:134:22: error: expected ')'
>>>>>  DECLARE_INIT_SECTION(STG_PREPARE);
>>>>>   ^
>>>>>  include/common/initcall.h:134:1

Re: Compilation fails on OS-X

2019-02-14 Thread Patrick Hemmer


On 2019/2/14 08:20, Frederic Lecaille wrote:
> On 2/14/19 1:32 PM, Frederic Lecaille wrote:
>> On 2/13/19 7:30 PM, Patrick Hemmer wrote:
>>>
>>>
>>> On 2019/2/13 10:29, Olivier Houchard wrote:
>>>> Hi Patrick,
>>>>
>>>> On Wed, Feb 13, 2019 at 10:01:01AM -0500, Patrick Hemmer wrote:
>>>>> On 2019/2/13 09:40, Aleksandar Lazic wrote:
>>>>>> Am 13.02.2019 um 14:45 schrieb Patrick Hemmer:
>>>>>>> Trying to compile haproxy on my local machine for testing
>>>>>>> purposes and am
>>>>>>> running into the following:
>>>>>> Which compiler do you use?
>>>>> # gcc -v
>>>>> Configured with:
>>>>> --prefix=/Applications/Xcode.app/Contents/Developer/usr
>>>>> --with-gxx-include-dir=/usr/include/c++/4.2.1
>>>>> Apple LLVM version 9.0.0 (clang-900.0.39.2)
>>>>> Target: x86_64-apple-darwin17.7.0
>>>>> Thread model: posix
>>>>> InstalledDir:
>>>>> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
>>>>>
>>>>>
>>>>>>>  # make TARGET=osx
>>>>>>>  src/proto_http.c:293:1: error: argument to 'section'
>>>>>>> attribute is not
>>>>>>> valid for this target: mach-o section specifier requires a
>>>>>>> segment and section
>>>>>>> separated by a comma
>>>>>>>  DECLARE_POOL(pool_head_http_txn, "http_txn",
>>>>>>> sizeof(struct http_txn));
>>>>>>>  ^
>>>>>>>  include/common/memory.h:128:2: note: expanded from
>>>>>>> macro 'DECLARE_POOL'
>>>>>>>  REGISTER_POOL(, name, size)
>>>>>>>  ^
>>>>>>>  include/common/memory.h:123:2: note: expanded from
>>>>>>> macro 'REGISTER_POOL'
>>>>>>>  INITCALL3(STG_POOL,
>>>>>>> create_pool_callback, (ptr), (name),
>>>>>>> (size))
>>>>>>>  ^
>>>>>>>  include/common/initcall.h:102:2: note: expanded from
>>>>>>> macro 'INITCALL3'
>>>>>>>  _DECLARE_INITCALL(stage, __LINE__,
>>>>>>> function, arg1, arg2,
>>>>>>> arg3)
>>>>>>>  ^
>>>>>>>  include/common/initcall.h:78:2: note: expanded from macro
>>>>>>> '_DECLARE_INITCALL'
>>>>>>>  __DECLARE_INITCALL(__VA_ARGS__)
>>>>>>>  ^
>>>>>>>  include/common/initcall.h:65:42: note: expanded from macro
>>>>>>> '__DECLARE_INITCALL'
>>>>>>> __attribute__((__used__,__section__("init_"#stg))) =   \
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Issue occurs on master, and the 1.9 branch
>>>>>>>
>>>>>>> -Patrick
>>>> Does the (totally untested, because I have no Mac to test) patch
>>>> works for
>>>> you ?
>>>
>>> Unfortunately not. Just introduces a lot of new errors:
>>>
>>>
>>>  In file included from src/ev_poll.c:22:
>>>  In file included from include/common/hathreads.h:26:
>>>  include/common/initcall.h:134:22: error: expected ')'
>>>  DECLARE_INIT_SECTION(STG_PREPARE);
>>>   ^
>>>  include/common/initcall.h:134:1: note: to match this '('
>>>  DECLARE_INIT_SECTION(STG_PREPARE);
>>>  ^
>>>  include/common/initcall.h:124:82: note: expanded from macro
>>> 'DECLARE_INIT_SECTION'
>>>  extern __attribute__((__weak__)) const struct
>>> initcall *__start_init_##stg __asm("section$start$__DATA$" stg); \
>>> ^
>>
>> Try to use -E in place of -c option of your compiler to stop after
>> having preprocessed the code. Then have a look to how the code of
>> src/ev_poll.c was preprocessed.
>>
>> This should help.
>>
>> Fred.
>
> As this sounds to be a preprocessing issue, and to have a l

Re: Compilation fails on OS-X

2019-02-13 Thread Patrick Hemmer


On 2019/2/13 10:29, Olivier Houchard wrote:
> Hi Patrick,
>
> On Wed, Feb 13, 2019 at 10:01:01AM -0500, Patrick Hemmer wrote:
>>
>> On 2019/2/13 09:40, Aleksandar Lazic wrote:
>>> Am 13.02.2019 um 14:45 schrieb Patrick Hemmer:
>>>> Trying to compile haproxy on my local machine for testing purposes and am
>>>> running into the following:
>>> Which compiler do you use?
>>  # gcc -v
>>  Configured with: 
>> --prefix=/Applications/Xcode.app/Contents/Developer/usr 
>> --with-gxx-include-dir=/usr/include/c++/4.2.1
>>  Apple LLVM version 9.0.0 (clang-900.0.39.2)
>>  Target: x86_64-apple-darwin17.7.0
>>  Thread model: posix
>>  InstalledDir: 
>> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
>>
>>>> # make TARGET=osx
>>>> src/proto_http.c:293:1: error: argument to 'section' attribute is 
>>>> not
>>>> valid for this target: mach-o section specifier requires a segment and 
>>>> section
>>>> separated by a comma
>>>> DECLARE_POOL(pool_head_http_txn, "http_txn", sizeof(struct 
>>>> http_txn));
>>>> ^
>>>> include/common/memory.h:128:2: note: expanded from macro 
>>>> 'DECLARE_POOL'
>>>> REGISTER_POOL(, name, size)
>>>> ^
>>>> include/common/memory.h:123:2: note: expanded from macro 
>>>> 'REGISTER_POOL'
>>>> INITCALL3(STG_POOL, create_pool_callback, (ptr), 
>>>> (name),
>>>> (size))
>>>> ^
>>>> include/common/initcall.h:102:2: note: expanded from macro 
>>>> 'INITCALL3'
>>>> _DECLARE_INITCALL(stage, __LINE__, function, arg1, 
>>>> arg2,
>>>> arg3)
>>>> ^
>>>> include/common/initcall.h:78:2: note: expanded from macro
>>>> '_DECLARE_INITCALL'
>>>> __DECLARE_INITCALL(__VA_ARGS__)
>>>> ^
>>>> include/common/initcall.h:65:42: note: expanded from macro
>>>> '__DECLARE_INITCALL'
>>>>
>>>> __attribute__((__used__,__section__("init_"#stg))) =   \
>>>>
>>>>
>>>>
>>>> Issue occurs on master, and the 1.9 branch
>>>>
>>>> -Patrick
> Does the (totally untested, because I have no Mac to test) patch works for
> you ?

Unfortunately not. Just introduces a lot of new errors:


In file included from src/ev_poll.c:22:
    In file included from include/common/hathreads.h:26:
include/common/initcall.h:134:22: error: expected ')'
DECLARE_INIT_SECTION(STG_PREPARE);
 ^
include/common/initcall.h:134:1: note: to match this '('
DECLARE_INIT_SECTION(STG_PREPARE);
^
include/common/initcall.h:124:82: note: expanded from macro
'DECLARE_INIT_SECTION'
extern __attribute__((__weak__)) const struct
initcall *__start_init_##stg __asm("section$start$__DATA$" stg); \

   
^

-Patrick


Re: Compilation fails on OS-X

2019-02-13 Thread Patrick Hemmer


On 2019/2/13 09:40, Aleksandar Lazic wrote:
> Am 13.02.2019 um 14:45 schrieb Patrick Hemmer:
>> Trying to compile haproxy on my local machine for testing purposes and am
>> running into the following:
> Which compiler do you use?

# gcc -v
Configured with: 
--prefix=/Applications/Xcode.app/Contents/Developer/usr 
--with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.0.0 (clang-900.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

>> # make TARGET=osx
>> src/proto_http.c:293:1: error: argument to 'section' attribute is not
>> valid for this target: mach-o section specifier requires a segment and 
>> section
>> separated by a comma
>> DECLARE_POOL(pool_head_http_txn, "http_txn", sizeof(struct 
>> http_txn));
>> ^
>> include/common/memory.h:128:2: note: expanded from macro 
>> 'DECLARE_POOL'
>> REGISTER_POOL(, name, size)
>> ^
>> include/common/memory.h:123:2: note: expanded from macro 
>> 'REGISTER_POOL'
>> INITCALL3(STG_POOL, create_pool_callback, (ptr), 
>> (name),
>> (size))
>> ^
>> include/common/initcall.h:102:2: note: expanded from macro 
>> 'INITCALL3'
>> _DECLARE_INITCALL(stage, __LINE__, function, arg1, 
>> arg2,
>> arg3)
>> ^
>> include/common/initcall.h:78:2: note: expanded from macro
>> '_DECLARE_INITCALL'
>> __DECLARE_INITCALL(__VA_ARGS__)
>> ^
>> include/common/initcall.h:65:42: note: expanded from macro
>> '__DECLARE_INITCALL'
>>
>> __attribute__((__used__,__section__("init_"#stg))) =   \
>>
>>
>>
>> Issue occurs on master, and the 1.9 branch
>>
>> -Patrick



Compilation fails on OS-X

2019-02-13 Thread Patrick Hemmer
Trying to compile haproxy on my local machine for testing purposes and
am running into the following:

# make TARGET=osx
src/proto_http.c:293:1: error: argument to 'section' attribute
is not valid for this target: mach-o section specifier requires a
segment and section separated by a comma
DECLARE_POOL(pool_head_http_txn, "http_txn", sizeof(struct
http_txn));
^
include/common/memory.h:128:2: note: expanded from macro
'DECLARE_POOL'
REGISTER_POOL(, name, size)
^
include/common/memory.h:123:2: note: expanded from macro
'REGISTER_POOL'
INITCALL3(STG_POOL, create_pool_callback, (ptr),
(name), (size))
^
include/common/initcall.h:102:2: note: expanded from macro
'INITCALL3'
_DECLARE_INITCALL(stage, __LINE__, function,
arg1, arg2, arg3)
^
include/common/initcall.h:78:2: note: expanded from macro
'_DECLARE_INITCALL'
__DECLARE_INITCALL(__VA_ARGS__)
^
include/common/initcall.h:65:42: note: expanded from macro
'__DECLARE_INITCALL'
   
__attribute__((__used__,__section__("init_"#stg))) =   \



Issue occurs on master, and the 1.9 branch

-Patrick


Re: Does anyone *really* use 51d or WURFL ?

2019-01-21 Thread Patrick Hemmer


On 2019/1/21 09:36, Willy Tarreau wrote:
> Hi all,
>
> recently it was figured that the buffer API changes caused some breakage
> to da.c and 51d.c (both fixed since), I don't know if wurfl builds at all
> by the way since the last update to the module is its introduction more
> than 2 years ago. But more importantly I'm realizing that neither 51d nor
> wurfl will start with threads enabled. This has been the case for about
> 15 months now, while we've had threads enabled on all relevant operating
> systems.
>
> Thus it leads me to the (possibly wrong) conclusion that absolutely
> nobody ever uses these options. Am I wrong ? I'm asking because each
> time we perform some API changes it's always a pain to go through these
> which don't build out of the box without external dependencies, and I
> suspect we're simply wasting our time and we should get rid of them
> if nobody uses them (or at the very least move them to contrib/).
>
> But if anyone is using them and disables threads for this, then it's
> fine, but in this case it would be nice if these two would check the
> thread safety of their code so that the thread restriction can be
> removed for the benefit of their users.
>
> Please advise.
>
> Thanks,
> Willy
>

We do use 51Degrees at my place of employment. However a couple of
caveats in that statement. One is that we're still running on 1.7. We'll
likely be upgrading to 1.9 soon, but still a couple months out.

The other caveat is that we run with threading disabled. Until the
statement on 'nbthread' that "THREADS SUPPORT IN HAPROXY IS HIGHLY
EXPERIMENTAL" goes away, we'll be leaving it off.

-Patrick


RE: haproxy AIX 7.1.0.0 compile issues

2018-12-27 Thread Overbey, Patrick (Sioux Falls)
Hi Willy,
Thanks for your prompt response. I appreciate your help with this matter.

Here is the ld version on my AIX system. 
ld: LD 1.65.6.6 (4/1/14)

I tried changing the linker in the Makefile from gcc to ld, but ran into 
similar undefined symbol errors. I installed binutils which includes gld 
version 2.29.1, but ran into many undefined reference errors (attached). 

Thank you!

Patrick Overbey
Fiserv


-Original Message-
From: Willy Tarreau [mailto:w...@1wt.eu] 
Sent: Thursday, December 27, 2018 8:17 AM
To: Overbey, Patrick (Sioux Falls) 
Cc: Aleksandar Lazic ; haproxy@formilux.org
Subject: Re: haproxy AIX 7.1.0.0 compile issues

Hi Patrick,

On Thu, Dec 27, 2018 at 01:37:15PM +, Overbey, Patrick (Sioux Falls) wrote:
> I have attached connection.c and vars.c (aixchg.tar.bz2) which had to 
> have changes to (ip_v and var) variable assignments to compile version 1.8.
> 
> I have also attached a build log (haproxy-make.zip) for version 1.9 
> when the build failed which has the same code changes to connection.c and 
> vars.c.

Thanks for your report. That's really sad that it broke, to say the least :-(

The problem that the change addressed was that we were dealing with init 
ordering dependencies that really required to do something finer than what we 
had till now. Certain things couldn't be pre-initialized (e.g. thread-local 
variables), resulting in the need to run through complex fixing operations when 
switching to multi-thread.

What you report indicates that your linker doesn't seem to create the start and 
end of section automatic symbols that we are relying on. 
Could you please send the output of "ld --version" ? I suspect it's not a 
binutils-compatible linker but there might be some options to make it become 
more compatible and/or to emit these symbols.

Alternatively maybe you have another linker available on the system.
Please check if you have something called "gld", "gcc-ld" or so, I wouldn't be 
surprised.

> When I attempt to add the -bnoquiet to the LDFLAGS, I get an error 
> that it is an unrecognized command line option. Here is the command I 
> used that included the -bnoquiet.
> 
> /usr/local/gnu-2018/bin/gmake -B CFLAGS="-maix64" LDFLAGS="-maix64 -bnoquiet"
> TARGET=aix52 USE_OPENSSL=1 SSL_INC=/opt/freeware/include/openssl
> SSL_LIB=/opt/freeware/lib USE_ZLIB=1 2>&1 | tee haproxy-make.log
> 
> gcc: error: unrecognized command line option '-bnoquiet'; did you mean 
> '-quiet'?

Regarding this one I'm less worried. We default to LD=$(CC) so by just setting 
"LD=ld" or wherever your ld is located, it should more or less be OK.

At the moment I'd really like to see how to make your linker generate the 
initcall symbols.

Regards,
Willy


haproxy-gld.log.bz2
Description: haproxy-gld.log.bz2


haproxy AIX 7.1.0.0 compile issues

2018-12-26 Thread Overbey, Patrick (Sioux Falls)
Hello,
First off, I want to say thank you for your hard work on haproxy. It is a very 
fine piece of software.
I recently ran into a bug compiling haproxy 1.9+ on AIX 7.1 7100-00-03-1115 
using gmake 4.2 and gcc 8.1.0. I had previously had 1.8 compiling using this 
same setup with a few minor code changes to variable names in vars.c and 
connection.c. I made those same changes in version 1.9, but have now ran into a 
compile issue that I cannot get around due to initcall.h being new in 1.9.

Here are the compile errors I am seeing.

ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
ld: 0711-317 ERROR: Undefined symbol: __start_init_STG_PREPARE
ld: 0711-317 ERROR: Undefined symbol: __stop_init_STG_PREPARE
ld: 0711-317 ERROR: Undefined symbol: __start_init_STG_LOCK
ld: 0711-317 ERROR: Undefined symbol: __stop_init_STG_LOCK
ld: 0711-317 ERROR: Undefined symbol: __start_init_STG_ALLOC
ld: 0711-317 ERROR: Undefined symbol: __stop_init_STG_ALLOC
ld: 0711-317 ERROR: Undefined symbol: __start_init_STG_POOL
ld: 0711-317 ERROR: Undefined symbol: __stop_init_STG_POOL
ld: 0711-317 ERROR: Undefined symbol: __start_init_STG_REGISTER
ld: 0711-317 ERROR: Undefined symbol: __stop_init_STG_REGISTER
ld: 0711-317 ERROR: Undefined symbol: __start_init_STG_INIT
ld: 0711-317 ERROR: Undefined symbol: __stop_init_STG_INIT

Would anyone have suggestions for how to fix this?

Also, as a note I am able to compile haproxy 1.5 out of the box, but starting 
with version 1.6 is where I run into compile errors. Is there support for these 
compile bugs or am I on my own?

Thanks for any help you can offer.

Patrick Overbey
Software Development Engineer Staff
Product Development/Bank Solutions
Office: 605-362-1260  x7290

Fiserv
Join us @ Forum 
2019<http://links.mkt030.com/ctt?kn=4=MjI3MTE3NzAS1=MjE1MjQ1MjExMTk0S0=0=MTMyNDU4NjM4OAS2=1=0>
Fiserv<http://links.mkt030.com/ctt?kn=3=MjI3MTE3NzAS1=MjE1MjQ1MjExMTk0S0=0=MTMyNDU4NjM4OAS2=1=0>
 | Join Our 
Team<http://links.mkt030.com/ctt?kn=7=MjI3MTE3NzAS1=MjE1MjQ1MjExMTk0S0=0=MTMyNDU4NjM4OAS2=1=0>
 | 
Twitter<http://links.mkt030.com/ctt?kn=1=MjI3MTE3NzAS1=MjE1MjQ1MjExMTk0S0=0=MTMyNDU4NjM4OAS2=1=0>
 | 
LinkedIn<http://links.mkt030.com/ctt?kn=5=MjI3MTE3NzAS1=MjE1MjQ1MjExMTk0S0=0=MTMyNDU4NjM4OAS2=1=0>
 | 
Facebook<http://links.mkt030.com/ctt?kn=9=MjI3MTE3NzAS1=MjE1MjQ1MjExMTk0S0=0=MTMyNDU4NjM4OAS2=1=0>
FORTUNE Magazine World's Most Admired Companies(r) 2014 | 2015 | 2016 | 2017 | 
2018
(c) 2018 Fiserv Inc. or its affiliates. Fiserv is a registered trademark of 
Fiserv Inc. Privacy Policy



Re: DNS resolution problem since 1.8.14

2018-12-24 Thread Patrick Valsecchi

Hi Jonathan,

I've build the 1.8.16 image myself and the problem is indeed fixed. Any 
plan of including that fix in a 1.9.1 release?


Thanks.

On 23.12.18 18:20, Jonathan Matthews wrote:

Hey Patrick,

Have you looked at the fixes in 1.8.16? They sound kinda-sorta related 
to your problem ...


J

On Sun, 23 Dec 2018 at 16:17, Patrick Valsecchi <mailto:patr...@thus.ch>> wrote:


I did a tcpdump. My config is modified to point to a local
container (www) in a docker compose (I'm trying to simplify my
setup). You can see the DNS answers correctly:

16:06:00.181533 IP (tos 0x0, ttl 64, id 63816, offset 0, flags
[DF], proto UDP (17), length 68)
    127.0.0.11.53 > localhost.40994: 63037 1/0/0 www. A
172.20.0.17 (40)

Could it be related to that?

https://github.com/haproxy/haproxy/commit/8d4e7dc880d2094658fead50dedd9c22c95c556a

On 23.12.18 13:59, Patrick Valsecchi wrote:


Hi,

Since haproxy version 1.8.14 and including the last 1.9 release,
haproxy puts all my backends in MAINT after around 31s. They
first work fine, but then they are put in MAINT.

The logs look like that:

<149>Dec 23 12:45:11 haproxy[1]: Proxy www started.
<149>Dec 23 12:45:11 haproxy[1]: Proxy plain started.
[NOTICE] 356/124511 (1) : New worker #1 (8) forked
<150>Dec 23 12:45:13 haproxy[8]: 89.217.194.174:49752
<http://89.217.194.174:49752> [23/Dec/2018:12:45:13.098]
plain www/linked 0/0/16/21/37 200 4197 - -  1/1/0/0/0 0/0
"GET / HTTP/1.1"
[WARNING] 356/124542 (8) : Server www/linked is going DOWN
for maintenance (DNS timeout status). 0 active and 0 backup
servers left. 0 sessions active, 0 requeued, 0 remaining in
queue.
<145>Dec 23 12:45:42 haproxy[8]: Server www/linked is going
DOWN for maintenance (DNS timeout status). 0 active and 0
backup servers left. 0 sessions active, 0 requeued, 0
remaining in queue.
[ALERT] 356/124542 (8) : backend 'www' has no server available!
<144>Dec 23 12:45:42 haproxy[8]: backend www has no server
available!

I run haproxy using docker:

docker run --name toto -ti --rm -v
/home/docker-compositions/web/proxy/conf.test:/etc/haproxy/:ro
-p 8080:80 haproxy:1.9 haproxy -f /etc/haproxy/

And my config is that:

global
    log stderr local2
    chroot  /tmp
    pidfile /run/haproxy.pid
    maxconn 4000
    max-spread-checks 500

    master-worker

    user    nobody
    group   nogroup

resolvers dns
  nameserver docker 127.0.0.11:53 <http://127.0.0.11:53>
  hold valid 1s

defaults
    mode    http
    log global
    option  httplog
    option  dontlognull
    option http-server-close
    option forwardfor   except 127.0.0.0/8
<http://127.0.0.0/8>
    option  redispatch
    retries 3
    timeout http-request    10s
    timeout queue   1m
    timeout connect 10s
    timeout client  10m
    timeout server  10m
    timeout http-keep-alive 10s
    timeout check   10s
    maxconn 3000
    default-server init-addr last,libc,none

    errorfile 400 /usr/local/etc/haproxy/errors/400.http
    errorfile 403 /usr/local/etc/haproxy/errors/403.http
    errorfile 408 /usr/local/etc/haproxy/errors/408.http
    errorfile 500 /usr/local/etc/haproxy/errors/500.http
    errorfile 502 /usr/local/etc/haproxy/errors/502.http
    errorfile 503 /usr/local/etc/haproxy/errors/503.http
    errorfile 504 /usr/local/etc/haproxy/errors/504.http

backend www
    option httpchk GET / HTTP/1.0\r\nUser-Agent:\ healthcheck
    http-check expect status 200
    default-server inter 60s fall 3 rise 1
    server linked www.topin.travel:80
<http://www.topin.travel:80> check resolvers dns

frontend plain
    bind :80

    http-request set-header X-Forwarded-Proto   http
    http-request set-header X-Forwarded-Host   
%[req.hdr(host)]
    http-request set-header X-Forwarded-Port    %[dst_port]
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Real-IP   %[src]

    compression algo gzip
    compression type text/css text/html text/javascript
application/javascript text/plain text/xml application/json

    # Forward to the main linked container

Re: DNS resolution problem since 1.8.14

2018-12-23 Thread Patrick Valsecchi
I did a tcpdump. My config is modified to point to a local container 
(www) in a docker compose (I'm trying to simplify my setup). You can see 
the DNS answers correctly:


   16:06:00.181533 IP (tos 0x0, ttl 64, id 63816, offset 0, flags [DF],
   proto UDP (17), length 68)
    127.0.0.11.53 > localhost.40994: 63037 1/0/0 www. A 172.20.0.17
   (40)

Could it be related to that? 
https://github.com/haproxy/haproxy/commit/8d4e7dc880d2094658fead50dedd9c22c95c556a


On 23.12.18 13:59, Patrick Valsecchi wrote:


Hi,

Since haproxy version 1.8.14 and including the last 1.9 release, 
haproxy puts all my backends in MAINT after around 31s. They first 
work fine, but then they are put in MAINT.


The logs look like that:

<149>Dec 23 12:45:11 haproxy[1]: Proxy www started.
<149>Dec 23 12:45:11 haproxy[1]: Proxy plain started.
[NOTICE] 356/124511 (1) : New worker #1 (8) forked
<150>Dec 23 12:45:13 haproxy[8]: 89.217.194.174:49752
[23/Dec/2018:12:45:13.098] plain www/linked 0/0/16/21/37 200 4197
- -  1/1/0/0/0 0/0 "GET / HTTP/1.1"
[WARNING] 356/124542 (8) : Server www/linked is going DOWN for
maintenance (DNS timeout status). 0 active and 0 backup servers
left. 0 sessions active, 0 requeued, 0 remaining in queue.
<145>Dec 23 12:45:42 haproxy[8]: Server www/linked is going DOWN
for maintenance (DNS timeout status). 0 active and 0 backup
servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
[ALERT] 356/124542 (8) : backend 'www' has no server available!
<144>Dec 23 12:45:42 haproxy[8]: backend www has no server available!

I run haproxy using docker:

docker run --name toto -ti --rm -v
/home/docker-compositions/web/proxy/conf.test:/etc/haproxy/:ro -p
8080:80 haproxy:1.9 haproxy -f /etc/haproxy/

And my config is that:

global
    log stderr local2
    chroot  /tmp
    pidfile /run/haproxy.pid
    maxconn 4000
    max-spread-checks 500

    master-worker

    user    nobody
    group   nogroup

resolvers dns
  nameserver docker 127.0.0.11:53
  hold valid 1s

defaults
    mode    http
    log global
    option  httplog
    option  dontlognull
    option http-server-close
    option forwardfor   except 127.0.0.0/8
    option  redispatch
    retries 3
    timeout http-request    10s
    timeout queue   1m
    timeout connect 10s
    timeout client  10m
    timeout server  10m
    timeout http-keep-alive 10s
    timeout check   10s
    maxconn 3000
    default-server init-addr last,libc,none

    errorfile 400 /usr/local/etc/haproxy/errors/400.http
    errorfile 403 /usr/local/etc/haproxy/errors/403.http
    errorfile 408 /usr/local/etc/haproxy/errors/408.http
    errorfile 500 /usr/local/etc/haproxy/errors/500.http
    errorfile 502 /usr/local/etc/haproxy/errors/502.http
    errorfile 503 /usr/local/etc/haproxy/errors/503.http
    errorfile 504 /usr/local/etc/haproxy/errors/504.http

backend www
    option httpchk GET / HTTP/1.0\r\nUser-Agent:\ healthcheck
    http-check expect status 200
    default-server inter 60s fall 3 rise 1
    server linked www.topin.travel:80 check resolvers dns

frontend plain
    bind :80

    http-request set-header X-Forwarded-Proto http
    http-request set-header X-Forwarded-Host %[req.hdr(host)]
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Real-IP %[src]

    compression algo gzip
    compression type text/css text/html text/javascript
application/javascript text/plain text/xml application/json

    # Forward to the main linked container by default
    default_backend www


Any idea what is happening? I've tried to increase the DNS resolve 
timeout to 5s and it didn't help. My feeling is that the newer 
versions of haproxy cannot talk with the DNS provided by docker.


Thanks



DNS resolution problem since 1.8.14

2018-12-23 Thread Patrick Valsecchi

Hi,

Since haproxy version 1.8.14 and including the last 1.9 release, haproxy 
puts all my backends in MAINT after around 31s. They first work fine, 
but then they are put in MAINT.


The logs look like that:

   <149>Dec 23 12:45:11 haproxy[1]: Proxy www started.
   <149>Dec 23 12:45:11 haproxy[1]: Proxy plain started.
   [NOTICE] 356/124511 (1) : New worker #1 (8) forked
   <150>Dec 23 12:45:13 haproxy[8]: 89.217.194.174:49752
   [23/Dec/2018:12:45:13.098] plain www/linked 0/0/16/21/37 200 4197 -
   -  1/1/0/0/0 0/0 "GET / HTTP/1.1"
   [WARNING] 356/124542 (8) : Server www/linked is going DOWN for
   maintenance (DNS timeout status). 0 active and 0 backup servers
   left. 0 sessions active, 0 requeued, 0 remaining in queue.
   <145>Dec 23 12:45:42 haproxy[8]: Server www/linked is going DOWN for
   maintenance (DNS timeout status). 0 active and 0 backup servers
   left. 0 sessions active, 0 requeued, 0 remaining in queue.
   [ALERT] 356/124542 (8) : backend 'www' has no server available!
   <144>Dec 23 12:45:42 haproxy[8]: backend www has no server available!

I run haproxy using docker:

   docker run --name toto -ti --rm -v
   /home/docker-compositions/web/proxy/conf.test:/etc/haproxy/:ro -p
   8080:80 haproxy:1.9 haproxy -f /etc/haproxy/

And my config is that:

   global
    log stderr local2
    chroot  /tmp
    pidfile /run/haproxy.pid
    maxconn 4000
    max-spread-checks 500

    master-worker

    user    nobody
    group   nogroup

   resolvers dns
  nameserver docker 127.0.0.11:53
  hold valid 1s

   defaults
    mode    http
    log global
    option  httplog
    option  dontlognull
    option http-server-close
    option forwardfor   except 127.0.0.0/8
    option  redispatch
    retries 3
    timeout http-request    10s
    timeout queue   1m
    timeout connect 10s
    timeout client  10m
    timeout server  10m
    timeout http-keep-alive 10s
    timeout check   10s
    maxconn 3000
    default-server init-addr last,libc,none

    errorfile 400 /usr/local/etc/haproxy/errors/400.http
    errorfile 403 /usr/local/etc/haproxy/errors/403.http
    errorfile 408 /usr/local/etc/haproxy/errors/408.http
    errorfile 500 /usr/local/etc/haproxy/errors/500.http
    errorfile 502 /usr/local/etc/haproxy/errors/502.http
    errorfile 503 /usr/local/etc/haproxy/errors/503.http
    errorfile 504 /usr/local/etc/haproxy/errors/504.http

   backend www
    option httpchk GET / HTTP/1.0\r\nUser-Agent:\ healthcheck
    http-check expect status 200
    default-server inter 60s fall 3 rise 1
    server linked www.topin.travel:80 check resolvers dns

   frontend plain
    bind :80

    http-request set-header X-Forwarded-Proto http
    http-request set-header X-Forwarded-Host %[req.hdr(host)]
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Real-IP %[src]

    compression algo gzip
    compression type text/css text/html text/javascript
   application/javascript text/plain text/xml application/json

    # Forward to the main linked container by default
    default_backend www


Any idea what is happening? I've tried to increase the DNS resolve 
timeout to 5s and it didn't help. My feeling is that the newer versions 
of haproxy cannot talk with the DNS provided by docker.


Thanks



lua time tracking

2018-10-01 Thread Patrick Hemmer
What are the thoughts around putting time tracking stats around LUA
calls? Just really basic info like how long a request spent running LUA
code. Similar to how we already have metrics for time spent in queue,
connecting, waiting on response, etc.

Currently I accomplish this manually by grabbing the timestamp at the
beginning and end of all LUA actions, store the duration in a
transaction variable, and add that variable to the log. But I was
wondering if this should instead have a native solution.
I see we already have `tune.lua.service-timeout`, so it appears some
timing data is already tracked. However one difference between that data
and my custom implementation is that mine includes sleep time. So we
might want to expose the LUA time as 2 different metrics: one as CPU run
time, and another as wall clock time.

The use case is that as we put more code into LUA scripts, we want to be
aware of the impact this code is having on the performance of the
requests, and the response times.

-Patrick


Re: [PATCH 2/2] MINOR: Add srv_conn_free sample fetch

2018-08-27 Thread Patrick Hemmer


On 2018/8/22 04:05, Willy Tarreau wrote:
> On Thu, Aug 09, 2018 at 06:46:29PM -0400, Patrick Hemmer wrote:
>> This adds the 'srv_conn_free([/])' sample fetch. This fetch
>> provides the number of available connections on the designated server.
> Fine with this as well, though just like with the previous one, I
> disagree with this special case of -1 and would rather only count
> the really available connections (i.e. 0 if it's not possible to
> use the server).
>
> Willy

Adjusted from previous submission to handle dynamic maxconn, maxconn <
currconn, and cleanup documentation note.

-Patrick
From 2e3a908f229a1fcc11381c602aa131284b165a63 Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Thu, 14 Jun 2018 18:01:35 -0400
Subject: [PATCH] MINOR: Add srv_conn_free sample fetch

This adds the 'srv_conn_free([/])' sample fetch. This fetch
provides the number of available connections on the designated server.
---
 doc/configuration.txt | 19 ---
 src/backend.c | 28 
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 6eec8c10b..513ef0c49 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13690,7 +13690,8 @@ be_conn_free([]) : integer
   servers are also not included, unless all other servers are down. If no
   backend name is specified, the current one is used. But it is also possible
   to check another backend. It can be used to use a specific farm when the
-  nominal one is full. See also the "be_conn" and "connslots" criteria.
+  nominal one is full. See also the "be_conn", "connslots", and "srv_conn_free"
+  criteria.
 
   OTHER CAVEATS AND NOTES: if any of the server maxconn, or maxqueue is 0
   (meaning unlimited), then this fetch clearly does not make sense, in which
@@ -13908,8 +13909,20 @@ srv_conn([/]) : integer
   evaluated. If  is omitted, then the server is looked up in the
   current backend. It can be used to use a specific farm when one server is
   full, or to inform the server about our view of the number of active
-  connections with it. See also the "fe_conn", "be_conn" and "queue" fetch
-  methods.
+  connections with it. See also the "fe_conn", "be_conn", "queue", and
+  "srv_conn_free" fetch methods.
+
+srv_conn_free([/]) : integer
+  Returns an integer value corresponding to the number of available connections
+  on the designated server, possibly including the connection being evaluated.
+  The value does not include queue slots. If  is omitted, then the
+  server is looked up in the current backend. It can be used to use a specific
+  farm when one server is full, or to inform the server about our view of the
+  number of active connections with it. See also the "be_conn_free" and
+  "srv_conn" fetch methods.
+
+  OTHER CAVEATS AND NOTES: If the server maxconn is 0, then this fetch clearly
+  does not make sense, in which case the value returned will be -1.
 
 srv_is_up([/]) : boolean
   Returns true when the designated server is UP, and false when it is either
diff --git a/src/backend.c b/src/backend.c
index 01bd4b161..5a22b0fd0 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1886,6 +1886,33 @@ smp_fetch_srv_conn(const struct arg *args, struct sample 
*smp, const char *kw, v
return 1;
 }
 
+/* set temp integer to the number of available connections on the server in 
the backend.
+ * Accepts exactly 1 argument. Argument is a server, other types will lead to
+ * undefined behaviour.
+ */
+static int
+smp_fetch_srv_conn_free(const struct arg *args, struct sample *smp, const char 
*kw, void *private)
+{
+   unsigned int maxconn;
+
+   smp->flags = SMP_F_VOL_TEST;
+   smp->data.type = SMP_T_SINT;
+
+   if (args->data.srv->maxconn == 0) {
+   /* one active server is unlimited, return -1 */
+   smp->data.u.sint = -1;
+   return 1;
+   }
+
+   maxconn = srv_dynamic_maxconn(args->data.srv);
+   if (maxconn > args->data.srv->cur_sess)
+   smp->data.u.sint = maxconn - args->data.srv->cur_sess;
+   else
+   smp->data.u.sint = 0;
+
+   return 1;
+}
+
 /* set temp integer to the number of connections pending in the server's queue.
  * Accepts exactly 1 argument. Argument is a server, other types will lead to
  * undefined behaviour.
@@ -1945,6 +1972,7 @@ static struct sample_fetch_kw_list smp_kws = {ILH, {
{ "nbsrv", smp_fetch_nbsrv,  ARG1(1,BE),  NULL, 
SMP_T_SINT, SMP_USE_INTRN, },
{ "queue", smp_fetch_queue_size, ARG1(1,BE),  NULL, 
SMP_T_SINT, SMP_USE_INTRN, },
{ "srv_conn",  smp_fetch_srv_conn,   ARG1(1,SRV), NULL, 
SMP_T_SINT,

Re: [PATCH 1/2] MINOR: add be_conn_free sample fetch

2018-08-25 Thread Patrick Hemmer


On 2018/8/25 01:30, Willy Tarreau wrote:
> On Fri, Aug 24, 2018 at 06:18:23PM -0400, Patrick Hemmer wrote:
>>> I disagree with making a special case above for maxconn 0. In fact for me
>>> it just means that such a server cannot accept connections, so it simply
>>> doesn't count in the sum, just as if it were not present.
>> On a server, maxconn=0 means unlimited, not that it can't accept
>> connections. If we return 0, how will the caller differentiate between
>> unlimited, and no free connections?
> Ah OK I didn't remember about this one, the it completely makes sense.
> Thanks for refreshing me on this one. It deserves a comment because it's
> not obvious ;-)  The current comment says the configuration is stupid
> while in fact it's just that this server is not limited. I think I
> still don't agree much with reporting -1 even if I'm the one having
> set it for connslots, which probably means I changed my mind regarding
> this. But I'm not seeing any better value that can easily be checked,
> so that's probably the least bad solution.
>
>> Also made 2 additional changes. One is to handle dynamic maxconn. The
>> other is to handle the case where the maxconn is adjusted (via stats
>> socket) to be less than the number of currently active connections,
>> which would result in the value wrapping.
> Good point. I'll adjust the doc then since it still says that it doesn't
> handle dynamic maxconn. Just let me know if you agree, and I'll do it
> myself to save you from having to respin a patch.
Sure, that's fine with me. Thanks :-)

>> Will update the srv_conn_free fetch with similar changes pending outcome
>> of this one.
> OK, thanks.
>
> Willy
I'll adjust the other sample fetch tomorrow.

-Patrick


Re: [PATCH 1/2] MINOR: add be_conn_free sample fetch

2018-08-24 Thread Patrick Hemmer


On 2018/8/22 04:04, Willy Tarreau wrote:
> Hi Patrick,
>
> On Thu, Aug 09, 2018 at 06:46:28PM -0400, Patrick Hemmer wrote:
>> This adds the sample fetch 'be_conn_free([])'. This sample fetch
>> provides the total number of unused connections across available servers
>> in the specified backend.
> Thanks for writing this one, I recently figured I needed the same for my
> build farm :-)
>
>> +be_conn_free([]) : integer
>> +  Returns an integer value corresponding to the number of available 
>> connections
>> +  across available servers in the backend. Queue slots are not included. 
>> Backup
>> +  servers are also not included, unless all other servers are down. If no
>> +  backend name is specified, the current one is used. But it is also 
>> possible
>> +  to check another backend. It can be used to use a specific farm when the
>> +  nominal one is full. See also the "be_conn" and "connslots" criteria.
>> +
>> +  OTHER CAVEATS AND NOTES: at this point in time, the code does not take 
>> care
>> +  of dynamic connections. Also, if any of the server maxconn, or maxqueue 
>> is 0,
>> +  then this fetch clearly does not make sense, in which case the value 
>> returned
>> +  will be -1.
> I disagree with making a special case above for maxconn 0. In fact for me
> it just means that such a server cannot accept connections, so it simply
> doesn't count in the sum, just as if it were not present.
On a server, maxconn=0 means unlimited, not that it can't accept
connections. If we return 0, how will the caller differentiate between
unlimited, and no free connections?
This is the same behavior provided by the `connslots` fetch, and is also
where I stole the doc snippet from.

>
>> +px = iterator->proxy;
>> +if (!srv_currently_usable(iterator) || ((iterator->flags & 
>> SRV_F_BACKUP) &&
>> +(px->srv_act ||
>> +(iterator != 
>> px->lbprm.fbck && !(px->options & PR_O_USE_ALL_BK)
>> +continue;
> Please slightly reorder the condition to improve the indent above for
> better readability, for example :
>
>   if (!srv_currently_usable(iterator) ||
>   ((iterator->flags & SRV_F_BACKUP) &&
>(px->srv_act || (iterator != px->lbprm.fbck && 
> !(px->options & PR_O_USE_ALL_BK)
>
> After checking, I'm OK with the condition :-)
>
>> +if (iterator->maxconn == 0) {
>> +/* configuration is stupid */
>> +smp->data.u.sint = -1;  /* FIXME: stupid value! */
>> +return 1;
>> +}
>> +
>> +smp->data.u.sint += (iterator->maxconn - iterator->cur_sess);
> Here I'd simply suggest this to replace the whole block :
>
>   if (iterator->maxconn > iterator->cur_sess)
>   smp->data.u.sint += (iterator->maxconn - 
> iterator->cur_sess);
>
> And then it can properly count available connections through all
> available servers, regardless of their individual configuration.
>
> Otherwise I'm fine with this patch.
>
> Thanks,
> Willy
Also made 2 additional changes. One is to handle dynamic maxconn. The
other is to handle the case where the maxconn is adjusted (via stats
socket) to be less than the number of currently active connections,
which would result in the value wrapping.

Will update the srv_conn_free fetch with similar changes pending outcome
of this one.

-Patrick
From 151d032b9cb396df47435742c03817818878f5af Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Thu, 14 Jun 2018 17:10:27 -0400
Subject: [PATCH 1/2] MINOR: add be_conn_free sample fetch

This adds the sample fetch 'be_conn_free([])'. This sample fetch
provides the total number of unused connections across available servers in the
specified backend.
---
 doc/configuration.txt | 15 ++-
 src/backend.c | 41 +
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 6e33f5994..f65efce95 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13682,7 +13682,20 @@ be_conn([]) : integer
   possibly including the connection being evaluated. If no backend name is
   specified, the current one is used. But it is also possible to check another
   backend. It can be used to use a specific farm when the nominal one is full.
-  See also the "fe_conn", "queue" and "be_sess_rate" criteria.
+  

[PATCH] MEDIUM: reset lua transaction between http requests

2018-08-22 Thread Patrick Hemmer
Not sure if this is the right approach, but this addresses the issue for me.
This should be backported to 1.8.

-Patrick
From 9087400de99a3925380cac4128a431cd48a09145 Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Wed, 22 Aug 2018 10:02:00 -0400
Subject: [PATCH] MEDIUM: reset lua transaction between http requests

Previously LUA code would maintain the transaction state between http requests,
resulting in things like txn:get_priv() retrieving data from a previous requst.
This addresses the issue by ensuring the LUA state is reset between requests.
---
 src/proto_http.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/proto_http.c b/src/proto_http.c
index a7a8dadd6..93c8857cd 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -4460,6 +4460,9 @@ void http_end_txn_clean_session(struct stream *s)
s->flags &= ~(SF_CURR_SESS|SF_REDIRECTABLE|SF_SRV_REUSED);
s->flags &= ~(SF_ERR_MASK|SF_FINST_MASK|SF_REDISP);
 
+   hlua_ctx_destroy(s->hlua);
+   s->hlua = NULL;
+
s->txn->meth = 0;
http_reset_txn(s);
s->txn->flags |= TX_NOT_FIRST | TX_WAIT_NEXT_RQ;
-- 
2.18.0



Re: BUG: LUA txn:get_priv() scoped to connection, not transaction

2018-08-22 Thread Patrick Hemmer


On 2018/8/22 05:16, Thierry Fournier wrote:
> Hi Patrick,
>
> Could you retry adding the keyword “local” before data. Unfortunately,
> by default, Lua variables are global.
>
Makes no difference, still get the same result. I don't think it would
do anything anyway as the `txn:get_priv()` will still return a value,
even if nil, and overwrite whatever is in a previous definition.

>
>> core.register_action("test", { "http-req" }, function(txn)
>> *local*data = txn:get_priv()
>> if not data then
>> data = 0
>> end
>> data = data + 1
>> print(string.format("set to %d", data))
>>     txn:set_priv(data)
>> end)
>
> BR,
> Thierry
>
>
>> On 22 Aug 2018, at 05:57, Patrick Hemmer > <mailto:hapr...@stormcloud9.net>> wrote:
>>
>> There is a bug in the current stable haproxy (1.8.13) where the LUA
>> function txn:get_priv() is returning data stored from other
>> transactions. This was discovered as we have code that triggers on
>> certain requests, and it was triggering on requests it should not
>> have been.
>>
>> You can reproduce with this config:
>> global
>> lua-load haproxy.lua
>>
>> defaults
>> mode http
>>
>> frontend f1
>> bind :8000
>> default_backend b1
>> http-request lua.test
>>
>> backend b1
>> http-request use-service lua.fakeserv
>>
>> And this lua file:
>> core.register_action("test", { "http-req" }, function(txn)
>> data = txn:get_priv()
>> if not data then
>> data = 0
>> end
>> data = data + 1
>> print(string.format("set to %d", data))
>> txn:set_priv(data)
>> end)
>>
>> core.register_service("fakeserv", "http", function(applet)
>> applet:set_status(200)
>> applet:start_response()
>> end)
>>
>> And this curl command:
>> curl http://localhost:8000 http://localhost:8000
>>
>> Which provides this output:
>> set to 1
>> set to 2
>>
>>
>>
>> Version information:
>> HA-Proxy version 1.8.13 2018/07/30
>> Copyright 2000-2018 Willy Tarreau 
>>
>> Build options :
>> TARGET  = osx
>> CPU = generic
>> CC  = gcc
>> CFLAGS  = -O0 -g -fno-strict-aliasing
>> -Wdeclaration-after-statement -fwrapv -fno-strict-overflow
>> -Wno-address-of-packed-member -Wno-null-dereference -Wno-unused-label
>> OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1
>>
>> Default settings :
>> maxconn = 2000, bufsize = 16384, maxrewrite = 1024,
>> maxpollevents = 200
>>
>> Built with OpenSSL version : OpenSSL 1.1.0h  27 Mar 2018
>> Running on OpenSSL version : OpenSSL 1.1.0h  27 Mar 2018
>> OpenSSL library supports TLS extensions : yes
>> OpenSSL library supports SNI : yes
>> OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
>> Built with Lua version : Lua 5.3.4
>> Built with transparent proxy support using:
>> Encrypted password support via crypt(3): yes
>> Built with PCRE version : 8.42 2018-03-20
>> Running on PCRE version : 8.42 2018-03-20
>> PCRE library supports JIT : no (USE_PCRE_JIT not set)
>> Built with zlib version : 1.2.11
>> Running on zlib version : 1.2.11
>> Compression algorithms supported : identity("identity"),
>> deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
>> Built with network namespace support.
>>
>> Available polling systems :
>>  kqueue : pref=300,  test result OK
>>  poll : pref=200,  test result OK
>>  select : pref=150,  test result OK
>> Total: 3 (3 usable), will use kqueue.
>>
>> Available filters :
>> [SPOE] spoe
>> [COMP] compression
>> [TRACE] trace
>>
>>
>> -Patrick
>



Re: connection leak (stuck in CLOSE_WAIT) on master

2018-08-21 Thread Patrick Hemmer


On 2018/8/9 01:01, Patrick Hemmer wrote:
> There's an issue on current master (287527a) where haproxy is losing
> track of its connections, and they're getting stuck in CLOSE_WAIT. And
> it's counting these connections towards limits (such as maxconn).
> Eventually maxconn is reached and everything starts queuing, and
> timing out.
>
> Here's an example:
> # lsof -p 25520
> COMMAND   PIDUSER   FD TYPE DEVICE  
> SIZE/OFFNODE NAME
> 
> haproxy 25520 phemmer0u CHR   16,5
> 0x1409380c1797 /dev/ttys005
> haproxy 25520 phemmer1u CHR   16,5
> 0x1409380c1797 /dev/ttys005
> haproxy 25520 phemmer2u CHR   16,5
> 0x1409380c1797 /dev/ttys005
> haproxy 25520 phemmer3u 
> KQUEUE   count=0, state=0xa
> haproxy 25520 phemmer4uunix 0x933b1c4c9ed396b7   
> 0t0 /tmp/haproxy.sock.25520.tmp
> haproxy 25520 phemmer5uIPv4 0x933b1c4cbf5fc73f   
> 0t0 TCP *:8001 (LISTEN)
> haproxy 25520 phemmer6uIPv4 0x933b1c4c925fe437   
> 0t0 UDP *:51977
> haproxy 25520 phemmer7 PIPE 0x933b1c4c9f89c457 
> 16384 ->0x933b1c4c9f89bf17
> haproxy 25520 phemmer8 PIPE 0x933b1c4c9f89bf17 
> 16384 ->0x933b1c4c9f89c457
> haproxy 25520 phemmer9uunix 0x933b1c4c9548c96f   
> 0t0 /tmp/haproxy.sock.25520.tmp
> haproxy 25520 phemmer   11uIPv4 0x933b1c4cc0cca73f   
> 0t0 TCP 127.0.0.1:8001->127.0.0.1:59199 (CLOSE_WAIT)
> haproxy 25520 phemmer   12uIPv4 0x933b1c4cbfd20ddf   
> 0t0 TCP 127.0.0.1:59200->127.0.0.1:8081 (CLOSE_WAIT)
>
>
> FD 11 was the client making the request to haproxy, and FD 12 was
> haproxy to the server.
>
> > show fd
> 4 : st=0x05(R:PrA W:pra) ev=0x01(heopI) [lc]
> cnext=-13 cprev=-2 tmask=0x1 umask=0x0 owner=0x7f852af08430
> iocb=0x10bb89c40(listener_accept) l.st=RDY fe=GLOBAL
> 5 : st=0x05(R:PrA W:pra) ev=0x01(heopI) [lc]
> cnext=-13 cprev=-2 tmask=0x1 umask=0x0 owner=0x7f852af08a40
> iocb=0x10bb89c40(listener_accept) l.st=RDY fe=f1
> 7 : st=0x05(R:PrA W:pra) ev=0x00(heopi) [lc]
> cnext=-3 cprev=0 tmask=0x1 umask=0x0 owner=0x10bbc2ca0
> iocb=0x10bbc2ca0(poller_pipe_io_handler)
> 9 : st=0x20(R:pra W:pRa) ev=0x00(heopi) [lc]
> cnext=-3 cprev=-2 tmask=0x1 umask=0x1 owner=0x7f852ae14550
> iocb=0x10bba60a0(conn_fd_handler) cflg=0x00201300 fe=GLOBAL mux=PASS
> mux_ctx=0x7f852ca0
>  11 : st=0x22(R:pRa W:pRa) ev=0x10(Heopi) [lc]
> cnext=-3 cprev=-2 tmask=0x1 umask=0x0 owner=0x7f852ae13ef0
> iocb=0x10bba60a0(conn_fd_handler) cflg=0x80241300 fe=f1 mux=PASS
> mux_ctx=0x7f852ae14080
>  12 : st=0x25(R:PrA W:pRa) ev=0x00(heopi) [Lc]
> cnext=-17 cprev=-2 tmask=0x1 umask=0x0 owner=0x7f852ca000c0
> iocb=0x10bba60a0(conn_fd_handler) cflg=0x00202306 sv=s1/b1 mux=PASS
> mux_ctx=0x7f852ae14bb0
>
> > show sess
> 0x7f852ae14140: proto=tcpv4 src=127.0.0.1:59199 fe=f1 be=b1
> srv=s1 ts=00 age=2m9s calls=6 rq[f=8840020h,i=0,an=8000h,rx=,wx=,ax=]
> rp[f=8040h,i=0,an=a0h,rx=,wx=,ax=] s0=[7,8h,fd=11,ex=]
> s1=[7,118h,fd=12,ex=] exp=
> 0x7f852ae14830: proto=unix_stream src=unix:1 fe=GLOBAL
> be= srv= ts=00 age=20s calls=3
> rq[f=40c08202h,i=0,an=00h,rx=,wx=,ax=]
> rp[f=c0048202h,i=0,an=00h,rx=,wx=,ax=] s0=[7,ch,fd=9,ex=]
> s1=[7,4018h,fd=-1,ex=] exp=23h59m
>
>
>
> Here's the config I'm using:
> global
> stats socket /tmp/haproxy.sock level admin
> defaults
> log 127.0.0.1:1234 daemon
> mode http
> option httplog
> timeout queue 5s
> frontend f1
> bind :8001
> default_backend b1
> backend b1
> server s1 127.0.0.1:8081 maxconn 1
>
>
> Log output around the time it broke:
> <30>Aug  9 00:45:56 haproxy[25520]: 127.0.0.1:59186
> [09/Aug/2018:00:45:56.620] f1 b1/s1 0/167/1/107/275 200 121 - - 
> 2/2/1/1/0 0/2 "GET / HTTP/1.1"
> <30>Aug  9 00:45:57 haproxy[25520]: 127.0.0.1:59189
> [09/Aug/2018:00:45:56.726] f1 b1/s1 0/169/1/108/278 200 121 - - 
> 2/2/1/1/0 0/2 "GET / HTTP/1.1"
> <30>Aug  9 00:45:57 haproxy[25520]: 127.0.0.1:59193
> [09/Aug/2018:00:45:56.948] f1 b1/s1 0/56/1/109/167 200 121 - - 
> 2/2/1/1/0 0/1 "GET / HTTP/1.1"
> <30>Aug  9 00:45:57 haproxy[25520]: 127.0.0.1:59196
> [09/A

Re: haproxy processing request of a disconnected client

2018-08-21 Thread Patrick Hemmer


On 2018/8/9 13:00, Patrick Hemmer wrote:
> So I just noticed the behavior that when a request is queued and the
> client closes the connection, once a server slot frees up that request
> is still sent to the server which processes it and sends a response back.
> What's even more interesting is that the log indicates that everything
> was processed normally. It basically says the response was sent back
> to the client just fine.
>
> Example config:
> global
> stats socket /tmp/haproxy.sock level admin
> defaults
> log 127.0.0.1:1234 daemon
> mode http
> option httplog
> timeout queue 5s
> frontend f1
> bind :8001
> default_backend b1
> backend b1
> server s1 127.0.0.1:8081 maxconn 1
>
> Log output:
> <30>Aug  9 12:50:40 haproxy[12384]: 127.0.0.1:64723
> [09/Aug/2018:12:50:35.167] f1 b1/s1 0/0/0/5106/5106 200 118 - - 
> 2/2/1/1/0 0/0 "GET /y HTTP/1.1"
> <30>Aug  9 12:50:45 haproxy[12384]: 127.0.0.1:64726
> [09/Aug/2018:12:50:35.526] f1 b1/s1 0/4749/0/5102/9851 200 118 - -
>  1/1/0/1/0 0/1 "GET /x HTTP/1.1"
>
> ^ In this, the server sleeps for 5 seconds, and then replies. I sent
> the request for /y, and then a request for /x, but killed the client
> on the /x request after 1 second. The request for /y was processed,
> but then so was the request for /x. The close flags ("") indicate
> everything went fine.
>
> Information:
>
> lsof:
> COMMAND   PIDUSER   FD TYPE DEVICE  
> SIZE/OFFNODE NAME
> ...
> haproxy 12384 phemmer0u CHR   16,5
> 0x140daf691797 /dev/ttys005
> haproxy 12384 phemmer1u CHR   16,5
> 0x140daf691797 /dev/ttys005
> haproxy 12384 phemmer2u CHR   16,5
> 0x140daf691797 /dev/ttys005
> haproxy 12384 phemmer3u 
> KQUEUE   count=0, state=0xa
> haproxy 12384 phemmer4uunix 0x933b1c4c8f54438f   
> 0t0 /tmp/haproxy.sock.12384.tmp
> haproxy 12384 phemmer5uIPv4 0x933b1c4cc16309ff   
> 0t0 TCP *:8001 (LISTEN)
> haproxy 12384 phemmer6uIPv4 0x933b1c4c8fef8977   
> 0t0 UDP *:62112
> haproxy 12384 phemmer7uIPv4 0x933b1c4cbf5fd9ff   
> 0t0 TCP 127.0.0.1:8001->127.0.0.1:64723 (ESTABLISHED)
> haproxy 12384 phemmer8uIPv4 0x933b1c4cc1546ddf   
> 0t0 TCP 127.0.0.1:64724->127.0.0.1:8081 (ESTABLISHED)
> haproxy 12384 phemmer9uIPv4 0x933b1c4cc1c6209f   
> 0t0 TCP 127.0.0.1:8001->127.0.0.1:64726 (CLOSE_WAIT)
>
> admin socket 'show fd':
>   4 : st=0x05(R:PrA W:pra) ev=0x01(heopI) [nlc] cache=0
> owner=0x7f93f3705010 iocb=0x107f82c40(listener_accept)
> tmask=0x umask=0xfffe l.st=RDY fe=GLOBAL
>   5 : st=0x05(R:PrA W:pra) ev=0x01(heopI) [nlc] cache=0
> owner=0x7f93f3705650 iocb=0x107f82c40(listener_accept)
> tmask=0x umask=0xfffe l.st=RDY fe=f1
>   7 : st=0x25(R:PrA W:pRa) ev=0x00(heopi) [nlc] cache=0
> owner=0x7f93f3708280 iocb=0x107f9e2e0(conn_fd_handler) tmask=0x1
> umask=0x0 cflg=0x80201306 fe=f1 mux=PASS mux_ctx=0x7f93f3708490
>   8 : st=0x25(R:PrA W:pRa) ev=0x00(heopi) [nLc] cache=0
> owner=0x7f93f340ede0 iocb=0x107f9e2e0(conn_fd_handler) tmask=0x1
> umask=0x0 cflg=0x00202306 sv=s1/b1 mux=PASS mux_ctx=0x7f93f350d0e0
>   9 : st=0x22(R:pRa W:pRa) ev=0x10(Heopi) [nlc] cache=0
> owner=0x7f93f510 iocb=0x107f9e2e0(conn_fd_handler) tmask=0x1
> umask=0x0 cflg=0x80241300 fe=f1 mux=PASS mux_ctx=0x7f93f5100210
>  10 : st=0x25(R:PrA W:pRa) ev=0x00(heopi) [nlc] cache=0
> owner=0x7f93f3708100 iocb=0x107f9e2e0(conn_fd_handler) tmask=0x1
> umask=0x0 cflg=0x00201306 fe=GLOBAL mux=PASS mux_ctx=0x7f93f350d1a0
>
> admin socket 'show sess':
> 0x7f93f37084c0: proto=tcpv4 src=127.0.0.1:64723 fe=f1 be=b1 srv=s1
> ts=08 age=2s calls=3 rq[f=48840200h,i=0,an=8000h,rx=,wx=,ax=]
> rp[f=8040h,i=0,an=a0h,rx=,wx=,ax=] s0=[7,8h,fd=7,ex=]
> s1=[7,118h,fd=8,ex=] exp=
> 0x7f93f5100240: proto=tcpv4 src=127.0.0.1:64726 fe=f1 be=b1
> srv= ts=08 age=2s calls=3
> rq[f=c800020h,i=0,an=8000h,rx=,wx=,ax=]
> rp[f=8000h,i=0,an=00h,rx=,wx=,ax=] s0=[7,8h,fd=9,ex=]
> s1=[2,110h,fd=-1,ex=2s] exp=2s
> 0x7f93f350d1d0: proto=unix_stream src=unix:1 fe=GLOBAL be=
> srv= ts=02 age=0s calls=1
> rq[f=40c08202h,i=0,an=00h,rx=10s,wx=,ax=]
> rp[f=80008002h,i=0,an=00h,rx=,wx=,ax=] s0=[7,8h,fd=10,ex=]
> s1=[7,4018h,fd=-1,ex=] exp=10s
>
> Version info:
> # ./haproxy -vv
> HA-Proxy version 1.8.13 2018/07/30
> Copyright 2000-2018 Will

Re: [PATCH 0/2] sample fetches for available connections

2018-08-21 Thread Patrick Hemmer


On 2018/8/9 18:46, Patrick Hemmer wrote:
> These are 2 new sample fetches which provide the available connections.
> The be_conn_free fetch is similar to connslots, but has significant
> difference in that it does not count queue slots, nor backup servers
> (unless all servers are down).
>
> These are intended to be useful in combination with the priority
> queuing, so you can see how many connections are available, perhaps for
> taking action when the number is low. For example by reserving
> connections for high-priority requests, and rejecting low priority ones.
>
> -Patrick
>
> Patrick Hemmer (2):
>   MINOR: add be_conn_free sample fetch
>   MINOR: Add srv_conn_free sample fetch
>
>  doc/configuration.txt | 34 +---
>  src/backend.c | 60 +++
>  2 files changed, 91 insertions(+), 3 deletions(-)
>

Is there any interest in this?

Sorry for all the pings, lots of emails which look like they might have
fallen off the radar.

-Patrick


Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2018-08-21 Thread Patrick Hemmer


On 2018/6/17 14:02, Baptiste wrote:
>
>
> Le dim. 17 juin 2018 à 14:10, Patrick Gansterer  <mailto:par...@paroga.com>> a écrit :
>
>
> > On 17 Jun 2018, at 13:36, Baptiste  <mailto:bed...@gmail.com>> wrote:
> >
> > Can they be used to validate oauth tokens too?
>
> Depends on the implementation of the tokens, but if they are
> HMACSHA256 signed JWT, it’s very easy to validate them in a lua
> script now.
>
>
> That's how I am doing it now.
> Just wanted to know if a combination of http rules could do the job.
> And be maybe faster.
>
> Baptiste

Any progress on this? I'd also be interested in seeing native HMAC
functions added, as I'm doing something similar to a HMAC that I'd love
to replace.

-Patrick


Re: BUG: Tw is negative with lua sleep

2018-08-21 Thread Patrick Hemmer


On 2018/7/18 09:03, Frederic Lecaille wrote:
> Hello Patrick,
>
> On 07/17/2018 03:59 PM, Patrick Hemmer wrote:
>> Ping?
>>
>> -Patrick
>>
>> On 2018/6/22 15:10, Patrick Hemmer wrote:
>>> When using core.msleep in lua, the %Tw metric is a negative value.
>>>
>>> For example with the following config:
>>> haproxy.cfg:
>>> global
>>> lua-load /tmp/haproxy.lua
>>>
>>> frontend f1
>>> mode http
>>> bind :8000
>>> default_backend b1
>>> log 127.0.0.1:1234 daemon
>>> log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\
>>> Tq=%Tq\ TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw
>>>
>>> backend b1
>>> mode http
>>> http-request use-service lua.foo
>>>
>>> haproxy.lua:
>>> core.register_service("foo", "http", function(applet)
>>> core.msleep(100)
>>> applet:set_status(200)
>>> applet:start_response()
>>> end)
>>>
>>> The log contains:
>>> Ta=104 Tc=0 Td=0 Th=0 Ti=0 Tq=104 TR=104 Tr=104 Tt=104 Tw=-104
>>>
>>> ^ TR also looks wrong, as it did not take 104ms to receive the full
>>> request.
>>>
>>> This is built from the commit before current master: d8fd2af
>>>
>>> -Patrick
>>
>
> The patch attached to this mail fixes this issue at least for %TR field.
>
> But I am not sure at all it is correct or if there is no remaining
> issues. For instance the LUA tcp callback also updates the tv_request
> log field.
>
> So, let's wait for Thierry's validation.
>
> Regards.
>

Any update on this?

-Patrick



BUG: LUA txn:get_priv() scoped to connection, not transaction

2018-08-21 Thread Patrick Hemmer
There is a bug in the current stable haproxy (1.8.13) where the LUA
function txn:get_priv() is returning data stored from other
transactions. This was discovered as we have code that triggers on
certain requests, and it was triggering on requests it should not have been.

You can reproduce with this config:
global
lua-load haproxy.lua

defaults
mode http

frontend f1
bind :8000
default_backend b1
http-request lua.test

backend b1
http-request use-service lua.fakeserv

And this lua file:
core.register_action("test", { "http-req" }, function(txn)
data = txn:get_priv()
if not data then
data = 0
end
data = data + 1
print(string.format("set to %d", data))
txn:set_priv(data)
end)

core.register_service("fakeserv", "http", function(applet)
applet:set_status(200)
applet:start_response()
end)

And this curl command:
curl http://localhost:8000 http://localhost:8000

Which provides this output:
set to 1
set to 2



Version information:
HA-Proxy version 1.8.13 2018/07/30
Copyright 2000-2018 Willy Tarreau 

Build options :
TARGET  = osx
CPU = generic
CC  = gcc
CFLAGS  = -O0 -g -fno-strict-aliasing
-Wdeclaration-after-statement -fwrapv -fno-strict-overflow
-Wno-address-of-packed-member -Wno-null-dereference -Wno-unused-label
OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_LUA=1 USE_PCRE=1

Default settings :
maxconn = 2000, bufsize = 16384, maxrewrite = 1024,
maxpollevents = 200

Built with OpenSSL version : OpenSSL 1.1.0h  27 Mar 2018
Running on OpenSSL version : OpenSSL 1.1.0h  27 Mar 2018
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
Built with Lua version : Lua 5.3.4
Built with transparent proxy support using:
Encrypted password support via crypt(3): yes
Built with PCRE version : 8.42 2018-03-20
Running on PCRE version : 8.42 2018-03-20
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Built with zlib version : 1.2.11
Running on zlib version : 1.2.11
Compression algorithms supported : identity("identity"),
deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with network namespace support.

Available polling systems :
 kqueue : pref=300,  test result OK
 poll : pref=200,  test result OK
 select : pref=150,  test result OK
Total: 3 (3 usable), will use kqueue.

Available filters :
[SPOE] spoe
[COMP] compression
[TRACE] trace


-Patrick


[PATCH] DOC: add documentation for prio_class and prio_offset sample fetches.

2018-08-13 Thread Patrick Hemmer
This adds documentation that was missed as part of 268a707.
---
 doc/configuration.txt | 11 +++
 1 file changed, 11 insertions(+)


diff --git a/doc/configuration.txt b/doc/configuration.txt
index 48b69a5bd..d11b63185 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13857,6 +13857,17 @@ nbsrv([]) : integer
   to handle some load. It is useful to report a failure when combined with
   "monitor fail".
 
+prio_class : integer
+  Returns the priority class of the current session for http mode or connection
+  for tcp mode. The value will be that set by the last call to "http-request
+  set-priority-class" or "tcp-request content set-priority-class".
+
+prio_offset : integer
+  Returns the priority offset of the current session for http mode or
+  connection for tcp mode. The value will be that set by the last call to
+  "http-request set-priority-offset" or "tcp-request content
+  set-priority-offset".
+
 proc : integer
   Returns an integer value corresponding to the position of the process calling
   the function, between 1 and global.nbproc. This is useful for logging and



Re: [PATCH 1/2] MEDIUM: add set-priority-class and set-priority-offset

2018-08-13 Thread Patrick Hemmer


On 2018/8/13 09:17, Aleksandar Lazic wrote:
> On 11/08/2018 14:48, Patrick Hemmer wrote:
>>
>
> [snipp]
>
>> To answer one of the earlier questions, I do plan on writing a blog
>> article yes. The question is when. I'm considering backporting this
>> feature to 1.8 for my own use at work, and if done, might wait for that
>> so I have some real world usage to comment on.
>
> That sounds very good. Due to the fact that this is a new feature I'm
> not sure if it will be back ported. It's not my decision but I think
> this would be a nice feature in 1.8 also.
It will not be officially backported to 1.8. The backport will be done
by me personally for my own use.

>
>> Willy's example use cases were spot on. But to add the use case which
>> triggered me to write this code: The intent is more for layer 7 DOS
>> mitigation. It's really hard to correctly identify bots vs real users.
>> You can usually get it right, but mis-identification is very easy. So
>> the idea here is that we would add a score to incoming requests based on
>> things like the user having a cookie, are they a registered user,
>> request rate, etc. Similar to how email spam filters work. Each one of
>> these things would increment or decrement the score, and then they would
>> be queued based on the result. Then when we do have a L7 attack, we only
>> give compute resources to the attackers when there are no real users in
>> the queue. Thus the users might see some slowdown, but it should be
>> minimal. And since we're not actually blocking an attacker, it makes it
>> much harder for them to figure out the criteria we're using to identify
>> them and get around it. And also since we're not blocking, users which
>> end up mis-identified as bots aren't impacted during normal operations,
>> only when we're under attack. And even then it should be minimal since
>> while a user might have triggered a few of the score rules, the bot
>> would have hopefully triggered more.
>
> Full ack here. This is a difficult topic which can create a lot of
> headache.
>
> Do you think to use one of the sample like DeviceAtlas or 51 or a more
> specific solution?
No. DeviceAtlas and 51degrees are not suitable for this task. All these
libraries do is analyze the UserAgent header (which is trivially easy to
fake). They do not do behavior analysis.

>
> Do you think about to use SPOE for the detection to offload the check
> mechanism?
SPOE can be utilized yes. There are many other services which can be
utilized as well, even some which have official integration with haproxy
such as Datadome <https://docs.datadome.co/docs/haproxy-setup>. The
queuing mechanism is meant to be the action taken upon detection, while
the detection itself can be anything, and is left up to the user. But
the configuration will need to be tailored to the system utilizing it.

>
> If this question / answers are some business secret then I fully
> understand when you can't answer it.
>
>> -Patrick
>
> Regards
> Aleks



Re: [PATCH 1/2] MEDIUM: add set-priority-class and set-priority-offset

2018-08-11 Thread Patrick Hemmer
>> The class just uses integers, not delays. Also it's an interesting case
>> you have here, as many sites prefer to *increase* the delay on the pay
>> button or even once there's anything in your cart. There's a reason :
>> visitors who don't find what they're looking for are likely to quit the
>> site, so you need to improve their experience while they're searching.
>> Once their shopping cart is filled with a few articles, they're not
>> willing to spend as much time looking for them again on another site,
>> so they're very likely to accept to wait (even if that scares them).
>> Thus by delaying their traffic you can improve others' experience. Yes
>> I know it's dirty, but I don't operate a shopping site :-)
>
> ;-)
>
>>>   http-request set-priority-offset 5s if LOGO
>>
>> That's a typically good example, yes, as nobody cares about the logo
>> being loaded fast.
>
> We are both not marketing peoples, these peoples would like to k... us
> for that setup ;-)
>
>>>   # as a sample expression can also be this, right?
>>>   http-request set-priority-class \
>>> %[req.fhdr(User-Agent),51d.single(DeviceType,IsMobile,IsTablet)]
>>
>> No, it takes a constant expression. I'm not sure whether it would
>> really make sense to make it support sample expressions. I'm not
>> necessarily against it, it's just that I think it comes with extra cost
>> and complexity for very low value in the end. Very likely you can do
>> this using 2 or 3 rules only.
Actually it does take a sample expression, not a constant. This was done
so that you could calculate a priority based on multiple criteria in the
request.
However if desired, we could make it behave like many of the sample
converters, where it either accepts a numeric value, or a variable name.

>
> Agree.
> For that then the doc should be changed, imho.
>
> ###
> +  The "set-priority-class" is used to set the queue priority class of
> the
> +  current request. The value must be a sample expression which
> converts to an
>
> +  integer in the range -2047..2047.
> ###
>
> How about this?
>
> +  The "set-priority-class" is used to set the queue priority class of
> the
> +  current request. The value must be a integer number between
> -2047..2047.
>
> for offset also
>
> I will create a PR for this as soon as we agree to the wording.
>
>>>   # could this work ?
>>>   use_backend high_priority if priority-class > 5
>>
>> We don't have a sample fetch to retrieve the value, but it would be
>> trivial to implement as the value is present in the stream. Feel free
>> to take a look at how priority-class and priority-offset work for this.
>> Right now you can already achieve this by setting a variable anyway,
>> but I can see value in using the class to take a routing decision.
>
> Well there are two, as far I understand the code proper.
>
> ### src/queue.c
> +static struct sample_fetch_kw_list smp_kws = {ILH, {
> +   { "prio_class", smp_fetch_priority_class, 0, NULL, SMP_T_SINT,
> SMP_USE_INTRN, },
> +   { "prio_offset", smp_fetch_priority_offset, 0, NULL,
> SMP_T_SINT, SMP_USE_INTRN, },
> +   { /* END */},
> ###
>
> I think they are used internally, what's the impact to change the
> "SMP_USE_INTRN" to something which can be used for external lookups?
You're able to use these sample fetches fine. SMP_USE_INTRN doesn't mean
it's not for use by users. It means the information comes from internal
haproxy state, not from the request content.
Although it appears I forgot the documentation for these. Oops. I'll get
that addressed and submit a patch shortly.

>
> Maybe in the next round.
> As you said for now we can set a variable and route based on that.
>
>> Cheers,
>> Willy
>
> Regards
> aleks

To answer one of the earlier questions, I do plan on writing a blog
article yes. The question is when. I'm considering backporting this
feature to 1.8 for my own use at work, and if done, might wait for that
so I have some real world usage to comment on.
Willy's example use cases were spot on. But to add the use case which
triggered me to write this code: The intent is more for layer 7 DOS
mitigation. It's really hard to correctly identify bots vs real users.
You can usually get it right, but mis-identification is very easy. So
the idea here is that we would add a score to incoming requests based on
things like the user having a cookie, are they a registered user,
request rate, etc. Similar to how email spam filters work. Each one of
these things would increment or decrement the score, and then they would
be queued based on the result. Then when we do have a L7 attack, we only
give compute resources to the attackers when there are no real users in
the queue. Thus the users might see some slowdown, but it should be
minimal. And since we're not actually blocking an attacker, it makes it
much harder for them to figure out the criteria we're using to identify
them and get around it. And also since we're not blocking, users which
end up mis-identified as bots aren't impacted during normal operations,
only when we're under attack. And even then it should be minimal since
while a user might have triggered a few of the score rules, the bot
would have hopefully triggered more.


-Patrick


Re: [PATCH 1/2] MEDIUM: add set-priority-class and set-priority-offset

2018-08-10 Thread Patrick Hemmer


On 2018/8/10 09:19, Willy Tarreau wrote:
> Hi Patrick,
>
> On Thu, Aug 09, 2018 at 06:29:33PM -0400, Patrick Hemmer wrote:
>> I also went and removed the queue position counter code from
>> stream_process_counters(), and the logging still appears to work fine
>> (but I could have easily missed some potential scenarios).
> OK nice!
>
>> In regards to the idea you added to the commit message on the queue index
>>> It could even be further improved to avoid manipulating the stream
>>> from the queue :
>>>   - queue_idx = initial position when enqueuing
>>>   - queue_idx = measured position when dequeuing
>> Because the stream can pass through multiple queues, we'd have to make
>> sure that every time we de-queue, that the stream code pulls the value
>> and increments itself. However looking at all the various places
>> pendconn_unlink() gets called, I think it would be difficult for the
>> stream code to know when the value needs to be pulled.
> In fact the only two ways to be queued multiple times are :
>   - get redispatched after a failed connection attempt to a server ; in
> this case the pendconn was already dequeued to connect to the first
> server so the state is unambigous
>
>   - being redistributed when a pendconn was lying in a server's queue
> and the server is marked down. In this case the pendconn is simply
> unlinked, process_stream is woken up and I don't know if we collect
> queue_idx during the call to process_stream before queuing again.
>
> Anyway this is very minor, I'd even say cosmetic. I'm pretty fine with
> the current state already!
>
>> Anyway, attached is the latest patch set for review again.
> I've applied it to a local temporary branch and am willing to merge it
> if you're OK. I've only adjusted 3 minor things :
>   - removed the warning in the 3rd patch's commit message mentioning
> the missing calls to pendconn_unlink() before logs, because these
> ones were finally moved to patch 1 but we didn't edit this message ;
>
>   - removed the now unused queue_idx from stream_process_counters()
> which emits a warning since it's unused
>
>   - removed the "__decl_hathreads(HA_SPINLOCK_T lock);" from struct
> pendconn that is a leftover from the rebase onto the last queue
> updates.
>
> So please just let me know, I'm ready ;-)
>
> Thanks,
> Willy
Those changes seem good to me.
Merge it!
Quite happy to see this done with. Any issues can be addressed as bug fixes.

Thanks

-Patrick


[PATCH 1/2] MINOR: add be_conn_free sample fetch

2018-08-09 Thread Patrick Hemmer

This adds the sample fetch 'be_conn_free([])'. This sample fetch
provides the total number of unused connections across available servers
in the
specified backend.
---
 doc/configuration.txt | 15 ++-
 src/backend.c | 38 ++
 2 files changed, 52 insertions(+), 1 deletion(-)


diff --git a/doc/configuration.txt b/doc/configuration.txt
index 48b69a5bd..b5c093e15 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13682,7 +13682,20 @@ be_conn([]) : integer
   possibly including the connection being evaluated. If no backend name is
   specified, the current one is used. But it is also possible to check another
   backend. It can be used to use a specific farm when the nominal one is full.
-  See also the "fe_conn", "queue" and "be_sess_rate" criteria.
+  See also the "fe_conn", "queue", "be_conn_free", and "be_sess_rate" criteria.
+
+be_conn_free([]) : integer
+  Returns an integer value corresponding to the number of available connections
+  across available servers in the backend. Queue slots are not included. Backup
+  servers are also not included, unless all other servers are down. If no
+  backend name is specified, the current one is used. But it is also possible
+  to check another backend. It can be used to use a specific farm when the
+  nominal one is full. See also the "be_conn" and "connslots" criteria.
+
+  OTHER CAVEATS AND NOTES: at this point in time, the code does not take care
+  of dynamic connections. Also, if any of the server maxconn, or maxqueue is 0,
+  then this fetch clearly does not make sense, in which case the value returned
+  will be -1.
 
 be_sess_rate([]) : integer
   Returns an integer value corresponding to the sessions creation rate on the
diff --git a/src/backend.c b/src/backend.c
index 1aadca590..c26304a2d 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1792,6 +1792,43 @@ smp_fetch_be_conn(const struct arg *args, struct sample *smp, const char *kw, vo
 	return 1;
 }
 
+/* set temp integer to the number of available connections across available
+	*	servers on the backend.
+ * Accepts exactly 1 argument. Argument is a backend, other types will lead to
+ * undefined behaviour.
+	*/
+static int
+smp_fetch_be_conn_free(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	struct server *iterator;
+	struct proxy *px;
+
+	smp->flags = SMP_F_VOL_TEST;
+	smp->data.type = SMP_T_SINT;
+	smp->data.u.sint = 0;
+
+	for (iterator = args->data.prx->srv; iterator; iterator = iterator->next) {
+		if (iterator->cur_state == SRV_ST_STOPPED)
+			continue;
+
+		px = iterator->proxy;
+		if (!srv_currently_usable(iterator) || ((iterator->flags & SRV_F_BACKUP) &&
+		(px->srv_act ||
+			(iterator != px->lbprm.fbck && !(px->options & PR_O_USE_ALL_BK)
+			continue;
+
+		if (iterator->maxconn == 0) {
+			/* configuration is stupid */
+			smp->data.u.sint = -1;  /* FIXME: stupid value! */
+			return 1;
+		}
+
+		smp->data.u.sint += (iterator->maxconn - iterator->cur_sess);
+	}
+
+	return 1;
+}
+
 /* set temp integer to the total number of queued connections on the backend.
  * Accepts exactly 1 argument. Argument is a backend, other types will lead to
  * undefined behaviour.
@@ -1897,6 +1934,7 @@ static int sample_conv_nbsrv(const struct arg *args, struct sample *smp, void *p
 static struct sample_fetch_kw_list smp_kws = {ILH, {
 	{ "avg_queue", smp_fetch_avg_queue_size, ARG1(1,BE),  NULL, SMP_T_SINT, SMP_USE_INTRN, },
 	{ "be_conn",   smp_fetch_be_conn,ARG1(1,BE),  NULL, SMP_T_SINT, SMP_USE_INTRN, },
+	{ "be_conn_free",  smp_fetch_be_conn_free,   ARG1(1,BE),  NULL, SMP_T_SINT, SMP_USE_INTRN, },
 	{ "be_id", smp_fetch_be_id,  0,   NULL, SMP_T_SINT, SMP_USE_BKEND, },
 	{ "be_name",   smp_fetch_be_name,0,   NULL, SMP_T_STR,  SMP_USE_BKEND, },
 	{ "be_sess_rate",  smp_fetch_be_sess_rate,   ARG1(1,BE),  NULL, SMP_T_SINT, SMP_USE_INTRN, },



[PATCH 2/2] MINOR: Add srv_conn_free sample fetch

2018-08-09 Thread Patrick Hemmer

This adds the 'srv_conn_free([/])' sample fetch. This fetch
provides the number of available connections on the designated server.
---
 doc/configuration.txt | 21 ++---
 src/backend.c | 22 ++
 2 files changed, 40 insertions(+), 3 deletions(-)


diff --git a/doc/configuration.txt b/doc/configuration.txt
index b5c093e15..b909fdc51 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -13690,7 +13690,8 @@ be_conn_free([]) : integer
   servers are also not included, unless all other servers are down. If no
   backend name is specified, the current one is used. But it is also possible
   to check another backend. It can be used to use a specific farm when the
-  nominal one is full. See also the "be_conn" and "connslots" criteria.
+  nominal one is full. See also the "be_conn", "connslots", and "srv_conn_free"
+  criteria.
 
   OTHER CAVEATS AND NOTES: at this point in time, the code does not take care
   of dynamic connections. Also, if any of the server maxconn, or maxqueue is 0,
@@ -13898,8 +13899,22 @@ srv_conn([/]) : integer
   evaluated. If  is omitted, then the server is looked up in the
   current backend. It can be used to use a specific farm when one server is
   full, or to inform the server about our view of the number of active
-  connections with it. See also the "fe_conn", "be_conn" and "queue" fetch
-  methods.
+  connections with it. See also the "fe_conn", "be_conn", "queue", and
+  "srv_conn_free" fetch methods.
+
+srv_conn_free([/]) : integer
+  Returns an integer value corresponding to the number of available connections
+  on the designated server, possibly including the connection being evaluated.
+  The value does not include queue slots. If  is omitted, then the
+  server is looked up in the current backend. It can be used to use a specific
+  farm when one server is full, or to inform the server about our view of the
+  number of active connections with it. See also the "be_conn_free" and
+  "srv_conn" fetch methods.
+
+  OTHER CAVEATS AND NOTES: at this point in time, the code does not take care
+  of dynamic connections. Also, if any of the server maxconn, or maxqueue is 0,
+  then this fetch clearly does not make sense, in which case the value returned
+  will be -1.
 
 srv_is_up([/]) : boolean
   Returns true when the designated server is UP, and false when it is either
diff --git a/src/backend.c b/src/backend.c
index c26304a2d..4bba3f4dd 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -1883,6 +1883,27 @@ smp_fetch_srv_conn(const struct arg *args, struct sample *smp, const char *kw, v
 	return 1;
 }
 
+/* set temp integer to the number of available connections on the server in the backend.
+ * Accepts exactly 1 argument. Argument is a server, other types will lead to
+ * undefined behaviour.
+ */
+static int
+smp_fetch_srv_conn_free(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	smp->flags = SMP_F_VOL_TEST;
+	smp->data.type = SMP_T_SINT;
+
+	if (args->data.srv->maxconn == 0) {
+			/* configuration is stupid */
+			smp->data.u.sint = -1;  /* FIXME: stupid value! */
+			return 1;
+	}
+
+	smp->data.u.sint = args->data.srv->maxconn - args->data.srv->cur_sess;
+
+	return 1;
+}
+
 /* set temp integer to the number of connections pending in the server's queue.
  * Accepts exactly 1 argument. Argument is a server, other types will lead to
  * undefined behaviour.
@@ -1942,6 +1963,7 @@ static struct sample_fetch_kw_list smp_kws = {ILH, {
 	{ "nbsrv", smp_fetch_nbsrv,  ARG1(1,BE),  NULL, SMP_T_SINT, SMP_USE_INTRN, },
 	{ "queue", smp_fetch_queue_size, ARG1(1,BE),  NULL, SMP_T_SINT, SMP_USE_INTRN, },
 	{ "srv_conn",  smp_fetch_srv_conn,   ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, },
+	{ "srv_conn_free", smp_fetch_srv_conn_free,  ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, },
 	{ "srv_id",smp_fetch_srv_id, 0,   NULL, SMP_T_SINT, SMP_USE_SERVR, },
 	{ "srv_is_up", smp_fetch_srv_is_up,  ARG1(1,SRV), NULL, SMP_T_BOOL, SMP_USE_INTRN, },
 	{ "srv_queue", smp_fetch_srv_queue,  ARG1(1,SRV), NULL, SMP_T_SINT, SMP_USE_INTRN, },



[PATCH 0/2] sample fetches for available connections

2018-08-09 Thread Patrick Hemmer
These are 2 new sample fetches which provide the available connections.
The be_conn_free fetch is similar to connslots, but has significant
difference in that it does not count queue slots, nor backup servers
(unless all servers are down).

These are intended to be useful in combination with the priority
queuing, so you can see how many connections are available, perhaps for
taking action when the number is low. For example by reserving
connections for high-priority requests, and rejecting low priority ones.

-Patrick

Patrick Hemmer (2):
  MINOR: add be_conn_free sample fetch
  MINOR: Add srv_conn_free sample fetch

 doc/configuration.txt | 34 +---
 src/backend.c | 60 +++
 2 files changed, 91 insertions(+), 3 deletions(-)

-- 
2.18.0




Re: [PATCH 1/2] MEDIUM: add set-priority-class and set-priority-offset

2018-08-09 Thread Patrick Hemmer
Re-adding the mailing list.

On 2018/8/6 22:37, Willy Tarreau wrote:
> Hi Patrick,
>>> I *think* that the change made to stream_process_counters() is not needed,
>>> because stream_process_counters() is normally used to keep the stats up
>>> to date so that when refreshing the stats page they don't make huge jumps.
>>> If you faced any corner case that this part managed to address, I'm
>>> interested in taking a look.
>> If I recall correctly, the scenario this was meant to address was when a
>> connection was removed from the queue ungracefully (e.g. a timeout).
>> In process_stream(), s->do_log(s) is called, which needs the counters
>> updated. However in this flow, the counters wouldn't get updated until
>> stream_free(s) a few lines later. stream_process_counters() seemed to be
>> made to address this scenario, so I put the code there.
>> I'll review this again though.
> Now I remember I thought about this case initially and I think I figured
> a few rare cases where it could possibly not be enough (maybe for aborts
> processed in HTTP keep-alive but I'm not sure and I prefer not to say too
> much bullshit). I remember sometimes getting an incorrect queue length at
> log time. Thus I have added a few calls to pendconn_dequeue() before all
> calls to do_log() which in my opinion are more robust for the long term.
> Thus it probably means that we can safely get rid of the calls in
> stream_process_counters(), which would be nice.
>
>>> You will notice that the code was significantly simplified thanks to the
>>> most painful part you had to deal with : the possibility for the trylock
>>> to fail. Now there is no trylock anymore and it cannot fail, so the very
>>> complex pendconn_next() is not needed anymore and I could replace it with
>>> a much simpler pendconn_first() which simply gives you the first element
>>> that is expected to be dequeued from a queue.
>> Found one spot in the code that looks like still falls into the scenario
>> where pendconn_next() is needed. This bit:
>>
>> int pendconn_redistribute(struct server *s)
>> ...
>> while ((p = pendconn_first(>pendconns))) {
>> if (p->strm_flags & SF_FORCE_PRST)
>> continue;
>>
>> This is going to infinitely loop.
> You're absolutely right, I didn't even notice this one! I think I was
> a bit too fast in replacing all loops with pendconn_first()!
>
>> An alternative option instead of pendconn_next() is on SF_FORCE_PRST we
>> build a new tree (or have some sort of temporary list), and pop them off
>> the current tree.
> In fact I don't think it's an issue, because here we need to remove all
> of them from the tree except the ones with the flag, so we don't even
> need to have something as complex as pendconn_next() to pop them up in
> order. Instead we can safely walk over the whole tree and only ignore
> SF_FORCE_PRST as the original code used to do, but using eb32_next().
> In fact my use of eb32_first() in the "while" loop in the previous
> patch was already wrong due to the "continue". We should simply have :
>
> for (node = eb32_first(>pendconns); node; node = eb32_next(node)) {
>   p = eb32_entry(, struct pendconn, node);
>   if (p->strm_flags & SF_FORCE_PRST)
>   continue;
>   ...
>   }
>
> If you want I'll update the patches once I'm at the office. Thanks for
> spotting this one.
>
> Willy
So I went and did that. It looks to work fine.
I also went and removed the queue position counter code from
stream_process_counters(), and the logging still appears to work fine
(but I could have easily missed some potential scenarios).

In regards to the idea you added to the commit message on the queue index
> It could even be further improved to avoid manipulating the stream
> from the queue :
>   - queue_idx = initial position when enqueuing
>   - queue_idx = measured position when dequeuing

Because the stream can pass through multiple queues, we'd have to make
sure that every time we de-queue, that the stream code pulls the value
and increments itself. However looking at all the various places
pendconn_unlink() gets called, I think it would be difficult for the
stream code to know when the value needs to be pulled.

Anyway, attached is the latest patch set for review again.

-Patrick
From e4acba5847fb11981c72af8430f6e6846211954f Mon Sep 17 00:00:00 2001
From: Patrick Hemmer 
Date: Fri, 11 May 2018 12:52:31 -0400
Subject: [PATCH 6/7] MEDIUM: queue: adjust position based on priority-class
 and priority-offset

The priority values are used when connections are queued to de

haproxy processing request of a disconnected client

2018-08-09 Thread Patrick Hemmer
SL 1.1.0h  27 Mar 2018
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2
Built with Lua version : Lua 5.3.4
Built with transparent proxy support using:
Encrypted password support via crypt(3): yes
Built with PCRE version : 8.42 2018-03-20
Running on PCRE version : 8.42 2018-03-20
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Built with zlib version : 1.2.11
Running on zlib version : 1.2.11
Compression algorithms supported : identity("identity"),
deflate("deflate"), raw-deflate("deflate"), gzip("gzip")
Built with network namespace support.

Available polling systems :
 kqueue : pref=300,  test result OK
 poll : pref=200,  test result OK
 select : pref=150,  test result OK
Total: 3 (3 usable), will use kqueue.

Available filters :
[SPOE] spoe
[COMP] compression
[TRACE] trace

-Patrick


Re: haproxy and changing ELB IPs

2018-08-07 Thread Patrick Hemmer


On 2018/8/7 05:45, Lukas Tribus wrote:
> Hello,
>
>
>> We recently had an outage for short time related to NameServer's h/w failure 
>> (both primary and secondary went down).
>> We were told that it is possible for these IPs to change in the future. It 
>> never happened so far though.
> So you don't have changing nameservers at all, but it is possible that
> the IPs will change once.
>
> I suggest you don't over-engineer this. Automating a possible one time
> occurrence is a waste of time, imho.
>
>
>> is it possible to optionally log the NS IPs during every health check?
> No.
>
>
>> Would a reload suffice instead of restart? It should not be difficult to 
>> create a monitor
>> for resolv.conf file using inotify lets say and automatically reload/restart 
>> haproxy in case
>> it's content has changed.
> Sure, a reload would suffice.
>
>
> Regards,
> Lukas
>
As an alternative option, if the system utilizes NetworkManager, then
solving this becomes very easy. NetworkManager can be configured to
provide a local dnsmasq instance as a DNS proxy. If this is enabled,
then your resolver becomes a static "127.0.0.1". And since
NetworkManager also integrates with the DHCP client, if the nameserver
IPs change, then it'll reload dnsmasq, and you don't need to do anything
with haproxy.
Enabling this is as simple as adding "dns = dnsmasq" to NetworkManager.conf.

-Patrick


Re: BUG: Tw is negative with lua sleep

2018-07-17 Thread Patrick Hemmer
Ping?

-Patrick

On 2018/6/22 15:10, Patrick Hemmer wrote:
> When using core.msleep in lua, the %Tw metric is a negative value.
>
> For example with the following config:
> haproxy.cfg:
> global
> lua-load /tmp/haproxy.lua
>
> frontend f1
> mode http
> bind :8000
> default_backend b1
> log 127.0.0.1:1234 daemon
> log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\ Tq=%Tq\
> TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw
>
> backend b1
> mode http
> http-request use-service lua.foo
>
> haproxy.lua:
> core.register_service("foo", "http", function(applet)
> core.msleep(100)
> applet:set_status(200)
> applet:start_response()
> end)
>
> The log contains:
> Ta=104 Tc=0 Td=0 Th=0 Ti=0 Tq=104 TR=104 Tr=104 Tt=104 Tw=-104
>
> ^ TR also looks wrong, as it did not take 104ms to receive the full
> request.
>
> This is built from the commit before current master: d8fd2af
>
> -Patrick



BUG: Tw is negative with lua sleep

2018-06-22 Thread Patrick Hemmer
When using core.msleep in lua, the %Tw metric is a negative value.

For example with the following config:
haproxy.cfg:
global
lua-load /tmp/haproxy.lua

frontend f1
mode http
bind :8000
default_backend b1
log 127.0.0.1:1234 daemon
log-format Ta=%Ta\ Tc=%Tc\ Td=%Td\ Th=%Th\ Ti=%Ti\ Tq=%Tq\
TR=%TR\ Tr=%Tr\ Tt=%Tt\ Tw=%Tw

backend b1
mode http
http-request use-service lua.foo

haproxy.lua:
core.register_service("foo", "http", function(applet)
core.msleep(100)
applet:set_status(200)
applet:start_response()
end)

The log contains:
Ta=104 Tc=0 Td=0 Th=0 Ti=0 Tq=104 TR=104 Tr=104 Tt=104 Tw=-104

^ TR also looks wrong, as it did not take 104ms to receive the full request.

This is built from the commit before current master: d8fd2af

-Patrick


BUG: cannot take the address of an rvalue of type 'unsigned long'

2018-06-22 Thread Patrick Hemmer
Trying to compile current master on OS-X, and get:

gcc -Iinclude -Iebtree -Wall  -O0 -g -fno-strict-aliasing
-Wdeclaration-after-statement -fwrapv -fno-strict-overflow 
-Wno-address-of-packed-member -Wno-null-dereference
-Wno-unused-label   -DTPROXY -DUSE_ZLIB  -DENABLE_POLL
-DENABLE_KQUEUE -DUSE_OPENSSL
-I/Users/phemmer/git/haproxy/openssl-1.1.0h/include -DUSE_LUA
-I/Users/phemmer/git/haproxy/lua-5.3.4/src
-I/Users/phemmer/git/haproxy/lua-5.3.4/src -DUSE_PCRE
-I/opt/local/include  -DCONFIG_HAPROXY_VERSION=\"1.9-dev0-ba86c6-462\"
-DCONFIG_HAPROXY_DATE=\"2018/06/22\" \
-DBUILD_TARGET='"osx"' \
-DBUILD_ARCH='""' \
-DBUILD_CPU='"generic"' \
-DBUILD_CC='"gcc"' \
-DBUILD_CFLAGS='"-O0 -g -fno-strict-aliasing
-Wdeclaration-after-statement -fwrapv -fno-strict-overflow
-Wno-address-of-packed-member -Wno-null-dereference -Wno-unused-label"' \
-DBUILD_OPTIONS='"USE_ZLIB=1 USE_OPENSSL=1
USE_LUA=1 USE_PCRE=1"' \
 -c -o src/haproxy.o src/haproxy.c
clang: warning: argument unused during compilation:
'-fno-strict-overflow' [-Wunused-command-line-argument]
src/haproxy.c:2476:16: error: cannot take the address of an
rvalue of type 'unsigned long'
HA_ATOMIC_AND(_threads_mask, ~tid_bit);
  ^
include/common/hathreads.h:41:42: note: expanded from macro
'HA_ATOMIC_AND'
#define HA_ATOMIC_AND(val, flags)({*(val) &= (flags);})
 ^~~
1 error generated.
make: *** [src/haproxy.o] Error 1

Built with: Apple LLVM version 9.0.0 (clang-900.0.39.2)

This broke in change ba86c6c:
commit ba86c6c25bf252e44589ae2b4d51a67c4f47d244 (HEAD -> master,
origin/master, origin/HEAD)
Author: Christopher Faulet 
Date:   Thu Jun 21 09:57:39 2018 +0200

MINOR: threads: Be sure to remove threads from all_threads_mask on exit
   
When HAProxy is started with several threads, Each running thread
holds a bit in
the bitfiled all_threads_mask. This bitfield is used here and there
to check
which threads are registered to take part in a specific processing.
So when a
thread exits, it seems normal to remove it from all_threads_mask.
   
No direct impact could be identified with this right now but it would
be better to backport it to 1.8 as a preventive measure to avoid complex
situations like the one in previous bug.



-Patrick


Re: [PATCH] MINOR: crypto: Add digest and hmac converters

2018-06-17 Thread Patrick Gansterer


> On 17 Jun 2018, at 13:36, Baptiste  wrote:
> 
> Can they be used to validate oauth tokens too?

Depends on the implementation of the tokens, but if they are HMACSHA256 signed 
JWT, it’s very easy to validate them in a lua script now.

> Note: maybe an update for configuration.txt would be helpful too.

Thx for the note. I’ve updated the patch.

- Patrick


[PATCH] MINOR: crypto: Add digest and hmac converters

2018-06-17 Thread Patrick Gansterer
Make the digest and HMAC function of OpenSSL accesable to the user via
converters. e.g. They can be used to sign and validate cookies.
---
 Makefile  |  2 +-
 doc/configuration.txt |  9 +
 src/crypto.c  | 84 +++
 3 files changed, 94 insertions(+), 1 deletion(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 5d170041..9a3a5024 100644
--- a/Makefile
+++ b/Makefile
@@ -609,7 +609,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl 
-lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/doc/configuration.txt b/doc/configuration.txt
index e901d7ee..7c9eb55c 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -12909,6 +12909,10 @@ debug
   type of the input sample. The sample is returned as is on its output. This
   converter only exists when haproxy was built with debugging enabled.
 
+digest()
+  Converts a binary input sample to a message digest. The result is a binary
+  sample. The alorithm must a OpenSSL message digest name (e.g sha256).
+
 div()
   Divides the input value of type signed integer by , and returns the
   result as an signed integer. If  is null, the largest unsigned
@@ -12963,6 +12967,11 @@ hex2i
   Converts a hex string containing two hex digits per input byte to an
   integer. If the input value can not be converted, then zero is returned.
 
+hmac(, )
+  Converts a binary input sample to a message authentication code with the 
given
+  key. The result is  a binary sample. The alorithm must be of the registered
+  OpenSSL message digest names (e.g sha256).
+
 http_date([])
   Converts an integer supposed to contain a date since epoch to a string
   representing this date in a format suitable for use in HTTP header fields. If
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index ..e4a65557
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,84 @@
+/*
+ * Crypto converters
+ *
+ * Copyright 2018 Patrick Gansterer 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+
+static int sample_conv_crypto_digest(const struct arg *args, struct sample 
*smp, void *private)
+{
+ struct chunk *trash = get_trash_chunk();
+ EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+ const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.str);
+ unsigned char *md = (unsigned char*) trash->str;
+ unsigned int md_len = trash->size;
+
+ if (!ctx)
+   return 0;
+ if (!evp)
+   return 0;
+
+ if (!EVP_DigestInit(ctx, evp) ||
+ !EVP_DigestUpdate(ctx, smp->data.u.str.str, smp->data.u.str.len) ||
+ !EVP_DigestFinal(ctx, md, _len)) {
+   EVP_MD_CTX_free(ctx);
+   return 0;
+ }
+
+ EVP_MD_CTX_free(ctx);
+
+ trash->len = md_len;
+ smp->data.u.str = *trash;
+ smp->data.type = SMP_T_BIN;
+ smp->flags &= ~SMP_F_CONST;
+ return 1;
+}
+
+static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, 
void *private)
+{
+ struct chunk *trash = get_trash_chunk();
+ const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.str);
+ const char* key = args[1].data.str.str;
+ int key_len = args[1].data.str.len;
+ unsigned char *md = (unsigned char*) trash->str;
+ unsigned int md_len = trash->size;
+
+ trash->len = 0;
+
+ if (!evp)
+   return 0;
+
+ if (!HMAC(evp, key, key_len, (const unsigned char*) smp->data.u.str.str, 
smp->data.u.str.len, md, _len))
+   return 0;
+
+ trash->len = md_len;
+ smp->data.u.str = *trash;
+ smp->data.type = SMP_T_BIN;
+ smp->flags &= ~SMP_F_CONST;
+ return 1;
+}
+
+static struct sample_conv_kw_list sample_conv_kws = {ILH, {
+ { "digest", sample_conv_crypto_digest, ARG1(1,STR), NULL, SMP_T_BIN, 
SMP_T_BIN },
+ { "hmac",   sample_conv_crypto_hmac,   ARG2(2,STR,STR), NULL, SMP_T_BIN, 
SMP_T_BIN },
+ { /* END */ },
+}};
+
+__attribute__((constructor))
+static void __crypto_init(void)
+{
+ sample_register_convs(_conv_kws);
+}
-- 
2.17.1




[PATCH] MINOR: crypto: Add digest and hmac converters

2018-06-17 Thread Patrick Gansterer
Make the digest and HMAC function of OpenSSL accesable to the user via
converters. e.g. They can be used to sign and validate cookies.
---
 Makefile |  2 +-
 src/crypto.c | 84 
 2 files changed, 85 insertions(+), 1 deletion(-)
 create mode 100644 src/crypto.c

diff --git a/Makefile b/Makefile
index 5d170041..9a3a5024 100644
--- a/Makefile
+++ b/Makefile
@@ -609,7 +609,7 @@ OPTIONS_LDFLAGS += $(if $(SSL_LIB),-L$(SSL_LIB)) -lssl 
-lcrypto
 ifneq ($(USE_DL),)
 OPTIONS_LDFLAGS += -ldl
 endif
-OPTIONS_OBJS  += src/ssl_sock.o
+OPTIONS_OBJS  += src/crypto.o src/ssl_sock.o
 endif
 
 # The private cache option affect the way the shctx is built
diff --git a/src/crypto.c b/src/crypto.c
new file mode 100644
index ..dcb343dc
--- /dev/null
+++ b/src/crypto.c
@@ -0,0 +1,84 @@
+/*
+ * Crypto converters
+ *
+ * Copyright 2018 Patrick Gansterer 
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+
+static int sample_conv_crypto_digest(const struct arg *args, struct sample 
*smp, void *private)
+{
+   struct chunk *trash = get_trash_chunk();
+   EVP_MD_CTX *ctx = EVP_MD_CTX_new();
+   const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.str);
+   unsigned char *md = (unsigned char*) trash->str;
+   unsigned int md_len = trash->size;
+
+   if (!ctx)
+   return 0;
+   if (!evp)
+   return 0;
+
+   if (!EVP_DigestInit(ctx, evp) ||
+   !EVP_DigestUpdate(ctx, smp->data.u.str.str, smp->data.u.str.len) ||
+   !EVP_DigestFinal(ctx, md, _len)) {
+   EVP_MD_CTX_free(ctx);
+   return 0;
+   }
+
+   EVP_MD_CTX_free(ctx);
+
+   trash->len = md_len;
+   smp->data.u.str = *trash;
+   smp->data.type = SMP_T_BIN;
+   smp->flags &= ~SMP_F_CONST;
+   return 1;
+}
+
+static int sample_conv_crypto_hmac(const struct arg *args, struct sample *smp, 
void *private)
+{
+   struct chunk *trash = get_trash_chunk();
+   const EVP_MD *evp = EVP_get_digestbyname(args[0].data.str.str);
+   const char* key = args[1].data.str.str;
+   int key_len = args[1].data.str.len;
+   unsigned char *md = (unsigned char*) trash->str;
+   unsigned int md_len = trash->size;
+
+   trash->len = 0;
+
+   if (!evp)
+   return 0;
+
+   if (!HMAC(evp, key, key_len, (const unsigned char*) 
smp->data.u.str.str, smp->data.u.str.len, md, _len))
+   return 0;
+
+   trash->len = md_len;
+   smp->data.u.str = *trash;
+   smp->data.type = SMP_T_BIN;
+   smp->flags &= ~SMP_F_CONST;
+   return 1;
+}
+
+static struct sample_conv_kw_list sample_conv_kws = {ILH, {
+   { "digest", sample_conv_crypto_digest, ARG1(1,STR), NULL, 
SMP_T_BIN, SMP_T_BIN },
+   { "hmac",   sample_conv_crypto_hmac,   ARG2(2,STR,STR), NULL, 
SMP_T_BIN, SMP_T_BIN },
+   { /* END */ },
+}};
+
+__attribute__((constructor))
+static void __crypto_init(void)
+{
+   sample_register_convs(_conv_kws);
+}
-- 
2.17.1


Re: [PATCH] BUG/MINOR: lua: Segfaults with wrong usage of types.

2018-06-15 Thread Patrick Hemmer


On 2018/6/15 09:06, Frederic Lecaille wrote:
> On 06/15/2018 02:28 PM, Frederic Lecaille wrote:
>> On 06/15/2018 02:15 PM, Frederic Lecaille wrote:
>>> On 06/14/2018 11:05 PM, Patrick Hemmer wrote:
>>>> Haproxy segfaults if you pass the wrong argument type to a converter.
>>>> Example:
>>>>
>>>> haproxy.cfg:
>>>>  global
>>>>  lua-load /tmp/haproxy.lua
>>>>
>>>>  frontend f1
>>>>  mode http
>>>>  bind :8000
>>>>  default_backend b1
>>>>
>>>>  http-request lua.foo
>>>>
>>>>  backend b1
>>>>  mode http
>>>>  server s1 127.0.0.1:8080
>>>>
>>>> haproxy.lua:
>>>>  core.register_action("foo", { "http-req" }, function(txn)
>>>>  txn.sc:ipmask(txn.f:src(), 24, 112)
>>>>  end)
>>>>
>>>> Result:
>>>>  * thread #1, queue = 'com.apple.main-thread', stop reason =
>>>> EXC_BAD_ACCESS (code=1, address=0x18)
>>>>  frame #0: 0x7fffc9fcbf56
>>>> libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 182
>>>> libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell:
>>>>  ->  0x7fffc9fcbf56 <+182>: movb   (%rsi,%r8), %cl
>>>>  0x7fffc9fcbf5a <+186>: movb   %cl, (%rdi,%r8)
>>>>  0x7fffc9fcbf5e <+190>: subq   $0x1, %rdx
>>>>  0x7fffc9fcbf62 <+194>: je 0x7fffc9fcbf78; <+216>
>>>>  Target 0: (haproxy) stopped.
>>>>  (lldb) bt
>>>>  * thread #1, queue = 'com.apple.main-thread', stop reason =
>>>> EXC_BAD_ACCESS (code=1, address=0x18)
>>>>* frame #0: 0x7fffc9fcbf56
>>>> libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 182
>>>>  frame #1: 0x7fffc9e7442e
>>>> libsystem_c.dylib`__memcpy_chk + 22
>>>>  frame #2: 0x00010002ec46
>>>> haproxy`hlua_lua2arg_check(L=0x00010120d298, first=3,
>>>> argp=0x7fff5fbfe690, mask=196, p=0x000101817000) at hlua.c:749
>>>>  frame #3: 0x00010001fa00
>>>> haproxy`hlua_run_sample_conv(L=0x00010120d298) at hlua.c:3393
>>>>  frame #4: 0x00010032400b haproxy`luaD_precall + 747
>>>>  frame #5: 0x0001003343c6 haproxy`luaV_execute + 3158
>>>>  frame #6: 0x000100323429 haproxy`luaD_rawrunprotected
>>>> + 89
>>>>  frame #7: 0x000100324516 haproxy`lua_resume + 278
>>>>  frame #8: 0x00010001b199
>>>> haproxy`hlua_ctx_resume(lua=0x000101205080, yield_allowed=1) at
>>>> hlua.c:1080
>>>>  frame #9: 0x000100027de8
>>>> haproxy`hlua_action(rule=0x00010101b180, px=0x000101817000,
>>>> sess=0x00010120cb70, s=0x00010120cc00, flags=2) at hlua.c:6198
>>>>  frame #10: 0x000100044bcd
>>>> haproxy`http_req_get_intercept_rule(px=0x000101817000,
>>>> rules=0x000101817048, s=0x00010120cc00,
>>>> deny_status=0x7fff5fbfee78) at proto_http.c:2760
>>>>  frame #11: 0x000100046182
>>>> haproxy`http_process_req_common(s=0x00010120cc00,
>>>> req=0x00010120cc10, an_bit=16, px=0x000101817000) at
>>>> proto_http.c:3461
>>>>  frame #12: 0x000100094c50
>>>> haproxy`process_stream(t=0x00010120cf40,
>>>> context=0x00010120cc00, state=9) at stream.c:1905
>>>>  frame #13: 0x00010016179f
>>>> haproxy`process_runnable_tasks at task.c:362
>>>>  frame #14: 0x0001000ea0eb haproxy`run_poll_loop at
>>>> haproxy.c:2403
>>>>  frame #15: 0x0001000e7c74
>>>> haproxy`run_thread_poll_loop(data=0x7fff5fbff3a4) at
>>>> haproxy.c:2464
>>>>  frame #16: 0x0001000e4a49 haproxy`main(argc=3,
>>>> argv=0x7fff5fbff590) at haproxy.c:3082
>>>>  frame #17: 0x7fffc9db9235 libdyld.dylib`start + 1
>>>>
>>>> Issue goes away if you change the lua txn.sc:ipmask() line to:
>>>>  txn.sc:ipmask(txn.f:src(), '24', '112')
>>>>
>>>> Reproduced with current master (9db0fed) and lua version 5.3.4.
>>>>
>>>> -Patrick
>>>
>>> It seems the patch attached to this mail fixes this issue. It at
>>> least make the varnishtest test file pass.
>>>
>>> Must be checked by Thierry.
>>
>> Should have mentionned that I could not reproduce this issue without
>> compiling the thread support (USE_THREAD=1).
>
> There is potentially the same issue in hlua_run_sample_conv(). See the
> updated patch attached to this mail.
>
>
I can confirm this patch addresses the segfault for my use case.

Thanks

-Patrick


BUG: segfault with lua sample converters & wrong arg types

2018-06-14 Thread Patrick Hemmer
Haproxy segfaults if you pass the wrong argument type to a converter.
Example:

haproxy.cfg:
global
lua-load /tmp/haproxy.lua
   
frontend f1
mode http
bind :8000
default_backend b1
   
http-request lua.foo
   
backend b1
mode http
server s1 127.0.0.1:8080

haproxy.lua:
core.register_action("foo", { "http-req" }, function(txn)
txn.sc:ipmask(txn.f:src(), 24, 112)
end)

Result:
* thread #1, queue = 'com.apple.main-thread', stop reason =
EXC_BAD_ACCESS (code=1, address=0x18)
frame #0: 0x7fffc9fcbf56
libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 182
libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell:
->  0x7fffc9fcbf56 <+182>: movb   (%rsi,%r8), %cl
0x7fffc9fcbf5a <+186>: movb   %cl, (%rdi,%r8)
0x7fffc9fcbf5e <+190>: subq   $0x1, %rdx
0x7fffc9fcbf62 <+194>: je 0x7fffc9fcbf78; <+216>
Target 0: (haproxy) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason =
EXC_BAD_ACCESS (code=1, address=0x18)
  * frame #0: 0x7fffc9fcbf56
libsystem_platform.dylib`_platform_memmove$VARIANT$Haswell + 182
frame #1: 0x7fffc9e7442e libsystem_c.dylib`__memcpy_chk + 22
frame #2: 0x00010002ec46
haproxy`hlua_lua2arg_check(L=0x00010120d298, first=3,
argp=0x7fff5fbfe690, mask=196, p=0x000101817000) at hlua.c:749
frame #3: 0x00010001fa00
haproxy`hlua_run_sample_conv(L=0x00010120d298) at hlua.c:3393
frame #4: 0x00010032400b haproxy`luaD_precall + 747
frame #5: 0x0001003343c6 haproxy`luaV_execute + 3158
frame #6: 0x000100323429 haproxy`luaD_rawrunprotected + 89
frame #7: 0x000100324516 haproxy`lua_resume + 278
frame #8: 0x00010001b199
haproxy`hlua_ctx_resume(lua=0x000101205080, yield_allowed=1) at
hlua.c:1080
frame #9: 0x000100027de8
haproxy`hlua_action(rule=0x00010101b180, px=0x000101817000,
sess=0x00010120cb70, s=0x00010120cc00, flags=2) at hlua.c:6198
frame #10: 0x000100044bcd
haproxy`http_req_get_intercept_rule(px=0x000101817000,
rules=0x000101817048, s=0x00010120cc00,
deny_status=0x7fff5fbfee78) at proto_http.c:2760
frame #11: 0x000100046182
haproxy`http_process_req_common(s=0x00010120cc00,
req=0x00010120cc10, an_bit=16, px=0x000101817000) at
proto_http.c:3461
frame #12: 0x000100094c50
haproxy`process_stream(t=0x00010120cf40, context=0x00010120cc00,
state=9) at stream.c:1905
frame #13: 0x00010016179f haproxy`process_runnable_tasks at
task.c:362
frame #14: 0x0001000ea0eb haproxy`run_poll_loop at
haproxy.c:2403
frame #15: 0x0001000e7c74
haproxy`run_thread_poll_loop(data=0x7fff5fbff3a4) at haproxy.c:2464
frame #16: 0x0001000e4a49 haproxy`main(argc=3,
argv=0x7fff5fbff590) at haproxy.c:3082
frame #17: 0x7fffc9db9235 libdyld.dylib`start + 1

Issue goes away if you change the lua txn.sc:ipmask() line to:
txn.sc:ipmask(txn.f:src(), '24', '112')

Reproduced with current master (9db0fed) and lua version 5.3.4.

-Patrick


Re: [Feature request] Call fan-out to all endpoints.

2018-06-10 Thread Patrick Hemmer


On 2018/6/10 13:27, Aleksandar Lazic wrote:
> Hi.
>
> On 10/06/2018 17:56, amotz wrote:
>> Baptiste wrote:
>>> Hi,
>>>
>>> what's the use case?
>>> Is this API gateway kind of thing?
>>>
>>> Baptiste
>>
>> From my experience this is mostly needed for operations/management API.
>>
>> Some examples:
>> getStaus (i.e get the status/health from all endpoint)
>> flashCache (make all endpoint flash their cache)
>> setConfig (you get the point ...)
>> more...
>>
>> with regard to the fan-in question by Jonathan.
>> Maybe return 207 (multi-status)  https://httpstatuses.com/207 ?
>> IMO, the most intuitive response would be a json array of all the
>> endpoints
>> responses, but I'm open for suggestions.
>
> Let's say you have a `option allendpoints /_fan-out`.
>
> When you now call `curl -sS https://haproxy:8080/_fan-out/health` then
> you will receive a json from *all active* endpoints (pods,
> app-server,...) with the result of there `/health`, something like this?
>
> That sounds interesting. Maybe it's possible with a
> `external-check command ` or some lua code?
>
> https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#external-check%20%28Alphabetically%20sorted%20keywords%20reference%29
>

Just throwing out my own $0.02, I don't think this is a good
responsibility for haproxy to support. This is very specific application
level logic.
Haproxy don't care about content types (json). What if I want to use
this feature, but with some other encoding?
How should haproxy respond if a server sends a 1GB response? It can't
buffer the whole thing in memory so it can encode it and add it to the
response message.
What about the non-happy-path cases? What if one of the servers times
out, what should haproxy put in the response? What if a server sends a
partial response?
How should the headers from a server response be encoded?

This is basically the invention of a new protocol.

Don't get me wrong, the underlying goal, having a client send a single
request and that request getting duplicated amongst the servers, is a
good one. In fact we do this at my work. But we use a custom application
that is specifically designed to handle the protocol we are wrapping.

I think this might be reasonable to do in LUA, and maybe even possible
already, but there's still going to be lots of the fore-mentioned
difficulties.
However to put some measure of positive spin on things, I think HTTP/2
would fit very well with this use case. HTTP/2 supports server push
messages. Meaning it's built in to the protocol that the client can send
a single request, and receive multiple responses. Haproxy doesn't
support fully H2 passthrough right now, but that may not be necessary. I
think LUA really only needs a few things to be able to support this: The
ability to receive H2 requests & generate responses (LUA already has
http/1.1 response capabilities, but I have no idea if they work with H2
requests), and then the ability to trigger a request to a server, and
have that sent back to the client as a server-push message.

-Patrick


Re: [PATCH 1/2] MEDIUM: add set-priority-class and set-priority-offset

2018-06-06 Thread Patrick Hemmer


On 2018/5/31 00:57, Willy Tarreau wrote:
> Hi Patrick,
>
> On Thu, May 31, 2018 at 12:16:27AM -0400, Patrick Hemmer wrote:
>>> I looked at the code to see if something could cause that. I found that the
>>> key increment could be a reason (you must restart from the next element,
>>> not an upper value since there will be many duplicate keys) 
>> Gah, I completely forgot about duplicate keys. Will fix.
> I'll send you (later today) some splitted patches that will help for
> this. This simplifies review and experimentations on the walk algorithm.
I kept the patch set you created, and have made some minor adjustments
to address the mentioned issues.

I think the only uncertainty I had during implementation was an atomic
operator for retrieving the queue_idx value inside
stream_process_counters. There's no load operator, but I'm not sure if
that is by design, or what the preferred solution is here. In theory if
the value is aligned, the load is atomic anyway and we don't need an
explicit atomic operator. But I'm not sure if that's an assumption we
want to make.

>> The warning is addressable. It means the user should add a `timeout
>> queue` and set it less than 524287ms. This is similar to the "missing
>> timeouts for frontend/backend" warning we print. Though I think it would
>> make sense to add "queue" to that existing warning instead, as it
>> already mentions the timeouts for client, connect & server.
> In fact the problem I'm having is that I've already seen some very high
> timeout values in field (eg on a print server), which means that some
> people do need to have a large value here. For sure they don't need to
> reach 24 days but 8min will definitely be too short for certain extreme
> cases. And I understand the impact of such large values with the queue,
> I just don't know how we can address this at the moment, it's what I'm
> still thinking about.
>
>>> We need to find a more suitable name for this "cntdepend" as it really 
>>> doesn't
>>> tell me that it has anything to do with what it says. I don't have anything
>>> to propose for now I'm afraid.
>> Yeah, not fond of the name, but it was something, and is easy to change.
>> The name originated from "cnt"=counter, and "pend" to be consistent with
>> the naming of "nbpend" and "totpend" right above it. So: counter of
>> de-queued pending connections.
> OK. In fact given that it's a wrapping counter it's why I considered it
> could be an index for the srv and px parts, but the stream part stores
> a distance between the recorded index and the current index.
>
>>> @@ -2467,6 +2469,10 @@ struct task *process_stream(struct task *t, void 
>>> *context, unsigned short state)
>>> return t; /* nothing more to do */
>>> }
>>>  
>>> +   // remove from pending queue here so we update counters
>>> +   if (s->pend_pos)
>>> +   pendconn_free(s->pend_pos);
>>> +
>>> if (s->flags & SF_BE_ASSIGNED)
>>> HA_ATOMIC_SUB(>be->beconn, 1);
>>>
>>> This part is not supposed to be needed since it's already performed
>>> in stream_free() a few lines later. Or if it's required to get the
>>> queue values correctly before logging, then something similar will
>>> be required at every place where we log after trying to connect to
>>> a server (there are a few places depending on the log format and
>>> the logasap option).
>> Yes, it was put there to update the counters before logging. Re-thinking
>> this, updating of the counters needs to be moved into
>> pendconn_process_next_stream anyway. Since this function updates
>> px->cntdepend and is called in a loop, calculating logs.prx_queue_pos
>> after this loop completes will yield incorrect values.
> I thought about the same but was not yet completely certain. I suspect in
> fact the stream's value should indeed be updated upon dequeue, and that
> only the error case has to be taken into account before logging (if there
> was no dequeue). In this case I think we can have this one performed here
> provided we ensure other log places will not be triggered on error.
>
>>> Now I think I understand how the cntdepend works : isn't it simply a
>>> wrapping queue index that you use to measure the difference between
>>> when you queued and when you dequeued ? In this case, wouldn't something
>>> like "queue_idx" be more explicit ? At least it becomes more obvious when
>>> doing the measure that we measure a length by subtracting two inde

  1   2   3   >