Backend connection issues with FIPS
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
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
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
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
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
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
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
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?
*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
*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
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
*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
*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
*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
*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
*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
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
*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
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
*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
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
*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
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
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
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
*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
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
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?
*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?
*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?
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
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
*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
*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?
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
*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
*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
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
*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
*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
*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
*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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 ?
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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
>> 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
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
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
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
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
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
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
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
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
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'
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
> 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
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
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.
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
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.
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
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