From aeb20f101c402ee1b8a86e6de3a93bd00924129d5eed007e434e9b817a0dac72 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Fri, 26 Sep 2014 08:52:30 +0000 Subject: [PATCH] Accepting request 252328 from network:ha-clustering:Factory 1 OBS-URL: https://build.opensuse.org/request/show/252328 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/haproxy?expand=0&rev=13 --- ...e-that-the-show-sess-output-format-i.patch | 35 +++ ...minor-typo-fix-in-stats_dump_errors_.patch | 28 +++ ...e-signal-handling-in-systemd-wrapper.patch | 105 +++++++++ ...pt-SIGHUP-SIGTERM-in-systemd-wrapper.patch | 48 ++++ ...the-doc-that-track-sc-can-wait-if-da.patch | 52 +++++ ...le-header-manipulation-for-101-respo.patch | 80 +++++++ ...g-propagate-frontend-to-backend-proc.patch | 60 +++++ ...operly-propagate-process-binding-bet.patch | 142 ++++++++++++ ...ke-the-frontends-automatically-bind-.patch | 93 ++++++++ ...mpute-the-exact-bind-process-before-.patch | 209 ++++++++++++++++++ ...ly-warn-if-stats-are-attached-to-mul.patch | 45 ++++ ...port-it-when-tcp-request-rules-are-m.patch | 110 +++++++++ ...ect-the-case-where-a-tcp-request-con.patch | 52 +++++ ...rapper-support-multiple-executable-v.patch | 90 ++++++++ ...e-debugging-code-from-systemd-wrappe.patch | 36 +++ haproxy.changes | 39 +++- haproxy.spec | 45 ++++ 17 files changed, 1268 insertions(+), 1 deletion(-) create mode 100644 0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch create mode 100644 0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch create mode 100644 0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch create mode 100644 0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch create mode 100644 0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch create mode 100644 0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch create mode 100644 0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch create mode 100644 0008-MEDIUM-config-properly-propagate-process-binding-bet.patch create mode 100644 0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch create mode 100644 0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch create mode 100644 0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch create mode 100644 0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch create mode 100644 0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch create mode 100644 0014-MEDIUM-systemd-wrapper-support-multiple-executable-v.patch create mode 100644 0015-BUG-MEDIUM-remove-debugging-code-from-systemd-wrappe.patch diff --git a/0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch b/0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch new file mode 100644 index 0000000..5209b95 --- /dev/null +++ b/0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch @@ -0,0 +1,35 @@ +From e99d44d4bc3423b721c7f654fd1778b9822a94e3 Mon Sep 17 00:00:00 2001 +From: Olivier +Date: Fri, 5 Sep 2014 18:49:10 +0200 +Subject: [PATCH 01/15] DOC: clearly state that the "show sess" output format + is not fixed + +It requires to look at the code (src/dumpstats.c) since the format may +change at any moment. +(cherry picked from commit ce31e6e3baebe75a2e6f6b5c66553db8d76dff0c) +--- + doc/configuration.txt | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 19df5ae..1ecf15a 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -13734,9 +13734,11 @@ show sess + of "show sess" (it corresponds to the session pointer). Those information are + useless to most users but may be used by haproxy developers to troubleshoot a + complex bug. The output format is intentionally not documented so that it can +- freely evolve depending on demands. The special id "all" dumps the states of +- all sessions, which can be avoided as much as possible as it is highly CPU +- intensive and can take a lot of time. ++ freely evolve depending on demands. You may find a description of all fields ++ returned in src/dumpstats.c ++ ++ The special id "all" dumps the states of all sessions, which must be avoided ++ as much as possible as it is highly CPU intensive and can take a lot of time. + + show stat [ ] + Dump statistics in the CSV format. By passing , and , it is +-- +1.8.4.5 + diff --git a/0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch b/0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch new file mode 100644 index 0000000..c882dc2 --- /dev/null +++ b/0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch @@ -0,0 +1,28 @@ +From 815d7d5c348575181874429b93b0ebdb0cf873c2 Mon Sep 17 00:00:00 2001 +From: Olivier Doucet +Date: Mon, 8 Sep 2014 11:23:00 +0200 +Subject: [PATCH 02/15] MINOR: stats: fix minor typo fix in + stats_dump_errors_to_buffer() + +Remove the space before the colon to match the format used in the frontend. +(cherry picked from commit 08afdcb47bc39c071787f8fc2066776e1c5e8607) +--- + src/dumpstats.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/dumpstats.c b/src/dumpstats.c +index 5365042..09bc7f6 100644 +--- a/src/dumpstats.c ++++ b/src/dumpstats.c +@@ -6045,7 +6045,7 @@ static int stats_dump_errors_to_buffer(struct stream_interface *si) + break; + case 1: + chunk_appendf(&trash, +- " backend %s (#%d) : invalid response\n" ++ " backend %s (#%d): invalid response\n" + " frontend %s (#%d)", + appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid, + es->oe->id, es->oe->uuid); +-- +1.8.4.5 + diff --git a/0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch b/0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch new file mode 100644 index 0000000..6e60d6d --- /dev/null +++ b/0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch @@ -0,0 +1,105 @@ +From 62c8565cd5bbda6ac0dd818fa26922eeaef1605c Mon Sep 17 00:00:00 2001 +From: Conrad Hoffmann +Date: Mon, 28 Jul 2014 23:52:20 +0200 +Subject: [PATCH 03/15] MEDIUM: Improve signal handling in systemd wrapper. + +Move all code out of the signal handlers, since this is potentially +dangerous. To make sure the signal handlers behave as expected, use +sigaction() instead of signal(). That also obsoletes messing with +the signal mask after restart. + +Signed-off-by: Conrad Hoffmann +(cherry picked from commit 5b5ea9c93384da49eea0f67ebed0966d4167b17a) +--- + src/haproxy-systemd-wrapper.c | 37 ++++++++++++++++++++++++------------- + 1 file changed, 24 insertions(+), 13 deletions(-) + +diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c +index 529b213..90a94ce 100644 +--- a/src/haproxy-systemd-wrapper.c ++++ b/src/haproxy-systemd-wrapper.c +@@ -22,6 +22,8 @@ + #define SD_DEBUG "<7>" + #define SD_NOTICE "<5>" + ++static volatile sig_atomic_t caught_signal; ++ + static char *pid_file = "/run/haproxy.pid"; + static int wrapper_argc; + static char **wrapper_argv; +@@ -103,7 +105,12 @@ static int read_pids(char ***pid_strv) + return read; + } + +-static void sigusr2_handler(int signum __attribute__((unused))) ++static void signal_handler(int signum) ++{ ++ caught_signal = signum; ++} ++ ++static void do_restart(void) + { + setenv(REEXEC_FLAG, "1", 1); + fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: re-executing\n"); +@@ -111,7 +118,7 @@ static void sigusr2_handler(int signum __attribute__((unused))) + execv(wrapper_argv[0], wrapper_argv); + } + +-static void sigint_handler(int signum __attribute__((unused))) ++static void do_shutdown(void) + { + int i, pid; + char **pid_strv = NULL; +@@ -147,25 +154,21 @@ int main(int argc, char **argv) + --argc; ++argv; + init(argc, argv); + +- signal(SIGINT, &sigint_handler); +- signal(SIGUSR2, &sigusr2_handler); ++ struct sigaction sa; ++ memset(&sa, 0, sizeof(struct sigaction)); ++ sa.sa_handler = &signal_handler; ++ sigaction(SIGUSR2, &sa, NULL); ++ sigaction(SIGINT, &sa, NULL); + + if (getenv(REEXEC_FLAG) != NULL) { + /* We are being re-executed: restart HAProxy gracefully */ + int i; + char **pid_strv = NULL; + int nb_pid = read_pids(&pid_strv); +- sigset_t sigs; + + unsetenv(REEXEC_FLAG); + spawn_haproxy(pid_strv, nb_pid); + +- /* Unblock SIGUSR2 which was blocked by the signal handler +- * before re-exec */ +- sigprocmask(SIG_BLOCK, NULL, &sigs); +- sigdelset(&sigs, SIGUSR2); +- sigprocmask(SIG_SETMASK, &sigs, NULL); +- + for (i = 0; i < nb_pid; ++i) + free(pid_strv[i]); + free(pid_strv); +@@ -176,8 +179,16 @@ int main(int argc, char **argv) + } + + status = -1; +- while (-1 != wait(&status) || errno == EINTR) +- ; ++ while (-1 != wait(&status) || errno == EINTR) { ++ if (caught_signal == SIGUSR2) { ++ caught_signal = 0; ++ do_restart(); ++ } ++ else if (caught_signal == SIGINT) { ++ caught_signal = 0; ++ do_shutdown(); ++ } ++ } + + fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: exit, haproxy RC=%d\n", + status); +-- +1.8.4.5 + diff --git a/0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch b/0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch new file mode 100644 index 0000000..ee4b399 --- /dev/null +++ b/0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch @@ -0,0 +1,48 @@ +From 6bb7bf7949dd019403b65f400c4b3d0d8589327b Mon Sep 17 00:00:00 2001 +From: Matt Robenolt +Date: Thu, 11 Sep 2014 05:19:30 +0000 +Subject: [PATCH 04/15] MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper + +My proposal is to let haproxy-systemd-wrapper also accept normal +SIGHUP/SIGTERM signals to play nicely with other process managers +besides just systemd. In my use case, this will be for using with +runit which has to ability to change the signal used for a +"reload" or "stop" command. It also might be worth renaming this +bin to just haproxy-wrapper or something of that sort to separate +itself away from systemd. But that's a different discussion. :) +(cherry picked from commit c54bdd2a118161b4dc36963b4201edfa7341dadb) +--- + src/haproxy-systemd-wrapper.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c +index 90a94ce..cc8baa8 100644 +--- a/src/haproxy-systemd-wrapper.c ++++ b/src/haproxy-systemd-wrapper.c +@@ -158,7 +158,9 @@ int main(int argc, char **argv) + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_handler = &signal_handler; + sigaction(SIGUSR2, &sa, NULL); ++ sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); ++ sigaction(SIGTERM, &sa, NULL); + + if (getenv(REEXEC_FLAG) != NULL) { + /* We are being re-executed: restart HAProxy gracefully */ +@@ -180,11 +182,11 @@ int main(int argc, char **argv) + + status = -1; + while (-1 != wait(&status) || errno == EINTR) { +- if (caught_signal == SIGUSR2) { ++ if (caught_signal == SIGUSR2 || caught_signal == SIGHUP) { + caught_signal = 0; + do_restart(); + } +- else if (caught_signal == SIGINT) { ++ else if (caught_signal == SIGINT || caught_signal == SIGTERM) { + caught_signal = 0; + do_shutdown(); + } +-- +1.8.4.5 + diff --git a/0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch b/0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch new file mode 100644 index 0000000..b5c5c88 --- /dev/null +++ b/0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch @@ -0,0 +1,52 @@ +From 531485c08ffb15b939a28ecf47090e4c93341d1b Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 15:48:15 +0200 +Subject: [PATCH 05/15] DOC: indicate in the doc that track-sc* can wait if + data are missing + +Since commit 1b71eb5 ("BUG/MEDIUM: counters: fix track-sc* to wait on +unstable contents"), we don't need the "if HTTP" anymore. But the doc +was not updated to reflect this. + +Since this change was backported to 1.5, this doc update should be +backported as well. +(cherry picked from commit 4d54c7ca0286588de5060acce9aff8aa9645bb98) +--- + doc/configuration.txt | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 1ecf15a..3c75c92 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -7470,9 +7470,9 @@ tcp-request content [{if | unless} ] + contents will always be immediately present when the rule is evaluated first. + + Tracking layer7 information is also possible provided that the information +- are present when the rule is processed. The current solution for making the +- rule engine wait for such information is to set an inspect delay and to +- condition its execution with an ACL relying on such information. ++ are present when the rule is processed. The rule processing engine is able to ++ wait until the inspect delay expires when the data to be tracked is not yet ++ available. + + Example: + # Accept HTTP requests containing a Host header saying "example.com" +@@ -7497,12 +7497,12 @@ tcp-request content [{if | unless} ] + Example: + # Track the last IP from X-Forwarded-For + tcp-request inspect-delay 10s +- tcp-request content track-sc0 hdr(x-forwarded-for,-1) if HTTP ++ tcp-request content track-sc0 hdr(x-forwarded-for,-1) + + Example: + # track request counts per "base" (concatenation of Host+URL) + tcp-request inspect-delay 10s +- tcp-request content track-sc0 base table req-rate if HTTP ++ tcp-request content track-sc0 base table req-rate + + Example: track per-frontend and per-backend counters, block abusers at the + frontend when the backend detects abuse. +-- +1.8.4.5 + diff --git a/0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch b/0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch new file mode 100644 index 0000000..dd5914c --- /dev/null +++ b/0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch @@ -0,0 +1,80 @@ +From 0cb4b899d370b9d04b3457a1d75dbd658c1a1646 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 10:40:38 +0200 +Subject: [PATCH 06/15] MEDIUM: http: enable header manipulation for 101 + responses + +Ryan Brock reported that server stickiness did not work for WebSocket +because the cookies and headers are not modified on 1xx responses. He +found that his browser correctly presents the cookies learned on 101 +responses, which was not specifically defined in the WebSocket spec, +nor in the cookie spec. 101 is a very special case. Being part of 1xx, +it's an interim response. But within 1xx, it's special because it's +the last HTTP/1 response that transits on the wire, which is different +from 100 or 102 which may appear multiple times. So in that sense, we +can consider it as a final response regarding HTTP/1, and it makes +sense to allow header processing there. Note that we still ensure not +to mangle the Connection header, which is critical for HTTP upgrade to +continue to work smoothly with agents that are a bit picky about what +tokens are found there. + +The rspadd rules are now processed for 101 responses as well, but the +cache-control checks are not performed (since no body is delivered). + +Ryan confirmed that this patch works for him. + +It would make sense to backport it to 1.5 given that it improves end +user experience on WebSocket servers. +(cherry picked from commit ce730de86719d0b5079dd8b0843559e4ff0a1ecc) +--- + src/proto_http.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/proto_http.c b/src/proto_http.c +index 4d27b2c..7e35c8b 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -6249,7 +6249,7 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit, + + /* add response headers from the rule sets in the same order */ + list_for_each_entry(wl, &rule_set->rsp_add, list) { +- if (txn->status < 200) ++ if (txn->status < 200 && txn->status != 101) + break; + if (wl->cond) { + int ret = acl_exec_cond(wl->cond, px, s, txn, SMP_OPT_DIR_RES|SMP_OPT_FINAL); +@@ -6270,7 +6270,7 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit, + } + + /* OK that's all we can do for 1xx responses */ +- if (unlikely(txn->status < 200)) ++ if (unlikely(txn->status < 200 && txn->status != 101)) + goto skip_header_mangling; + + /* +@@ -6283,7 +6283,7 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit, + /* + * Check for cache-control or pragma headers if required. + */ +- if ((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)) ++ if (((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)) && txn->status != 101) + check_response_for_cacheability(s, rep); + + /* +@@ -6399,9 +6399,11 @@ int http_process_res_common(struct session *s, struct channel *rep, int an_bit, + * Adjust "Connection: close" or "Connection: keep-alive" if needed. + * If an "Upgrade" token is found, the header is left untouched in order + * not to have to deal with some client bugs : some of them fail an upgrade +- * if anything but "Upgrade" is present in the Connection header. ++ * if anything but "Upgrade" is present in the Connection header. We don't ++ * want to touch any 101 response either since it's switching to another ++ * protocol. + */ +- if (!(txn->flags & TX_HDR_CONN_UPG) && ++ if ((txn->status != 101) && !(txn->flags & TX_HDR_CONN_UPG) && + (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) || + ((s->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL || + (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))) { +-- +1.8.4.5 + diff --git a/0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch b/0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch new file mode 100644 index 0000000..ef6c274 --- /dev/null +++ b/0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch @@ -0,0 +1,60 @@ +From b53934eec71ab34eb3762a89cec326360a5b0bc5 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 11:31:31 +0200 +Subject: [PATCH 07/15] BUG/MEDIUM: config: propagate frontend to backend + process binding again. + +This basically reverts 3507d5d ("MEDIUM: proxy: only adjust the backend's +bind-process when already set"). It was needed during the transition to +the new process binding method but is causing trouble now because frontend +to backend binding is not properly propagated. + +This fix should be backported to 1.5. +(cherry picked from commit 8a3478ed31a16904f45178c153f4649faf6de675) +--- + src/cfgparse.c | 15 ++++++--------- + 1 file changed, 6 insertions(+), 9 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 943eba0..5288600 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -6165,9 +6165,8 @@ int check_config_validity() + /* we force the backend to be present on at least all of + * the frontend's processes. + */ +- if (target->bind_proc) +- target->bind_proc = curproxy->bind_proc ? +- (target->bind_proc | curproxy->bind_proc) : 0; ++ target->bind_proc = curproxy->bind_proc ? ++ (target->bind_proc | curproxy->bind_proc) : 0; + + /* Emit a warning if this proxy also has some servers */ + if (curproxy->srv) { +@@ -6203,9 +6202,8 @@ int check_config_validity() + /* we force the backend to be present on at least all of + * the frontend's processes. + */ +- if (target->bind_proc) +- target->bind_proc = curproxy->bind_proc ? +- (target->bind_proc | curproxy->bind_proc) : 0; ++ target->bind_proc = curproxy->bind_proc ? ++ (target->bind_proc | curproxy->bind_proc) : 0; + } + } + } +@@ -6257,9 +6255,8 @@ int check_config_validity() + /* we force the backend to be present on at least all of + * the frontend's processes. + */ +- if (target->bind_proc) +- target->bind_proc = curproxy->bind_proc ? +- (target->bind_proc | curproxy->bind_proc) : 0; ++ target->bind_proc = curproxy->bind_proc ? ++ (target->bind_proc | curproxy->bind_proc) : 0; + } + } + +-- +1.8.4.5 + diff --git a/0008-MEDIUM-config-properly-propagate-process-binding-bet.patch b/0008-MEDIUM-config-properly-propagate-process-binding-bet.patch new file mode 100644 index 0000000..fccfe91 --- /dev/null +++ b/0008-MEDIUM-config-properly-propagate-process-binding-bet.patch @@ -0,0 +1,142 @@ +From 5436afc9488531a5e2adff3a1a766af375e0922c Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 12:17:36 +0200 +Subject: [PATCH 08/15] MEDIUM: config: properly propagate process binding + between proxies + +We now recursively propagate the bind-process values between frontends +and backends instead of doing it during name resolving. This ensures +that we're able to properly propagate all the bind-process directives +even across "listen" instances, which are not perfectly covered at the +moment, depending on the declaration order. +(cherry picked from commit 64ab6077b768ee02b04a36b30ee195639a2fabc1) +--- + src/cfgparse.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 65 insertions(+), 16 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 5288600..b9853ef 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -5932,6 +5932,64 @@ int readcfgfile(const char *file) + return err_code; + } + ++/* This function propagates processes from frontend to backend so ++ * that it is always guaranteed that a backend pointed to by a frontend is ++ * bound to all of its processes. After that, if the target is a "listen" ++ * instance, the function recursively descends the target's own targets along ++ * default_backend, use_backend rules, and reqsetbe rules. Since the bits are ++ * checked first to ensure that is already bound to all processes of ++ * , there is no risk of looping and we ensure to follow the shortest ++ * path to the destination. ++ * ++ * It is possible to set to NULL for the first call so that the function ++ * takes care of visiting the initial frontend in . ++ * ++ * It is important to note that the function relies on the fact that all names ++ * have already been resolved. ++ */ ++void propagate_processes(struct proxy *from, struct proxy *to) ++{ ++ struct switching_rule *rule; ++ struct hdr_exp *exp; ++ ++ if (to) { ++ /* check whether we need to go down */ ++ if (from->bind_proc && ++ (from->bind_proc & to->bind_proc) == from->bind_proc) ++ return; ++ ++ if (!from->bind_proc && !to->bind_proc) ++ return; ++ ++ to->bind_proc = from->bind_proc ? ++ (to->bind_proc | from->bind_proc) : 0; ++ ++ /* now propagate down */ ++ from = to; ++ } ++ ++ if (!from->cap & PR_CAP_FE) ++ return; ++ ++ /* default_backend */ ++ if (from->defbe.be) ++ propagate_processes(from, from->defbe.be); ++ ++ /* use_backend */ ++ list_for_each_entry(rule, &from->switching_rules, list) { ++ to = rule->be.backend; ++ propagate_processes(from, to); ++ } ++ ++ /* reqsetbe */ ++ for (exp = from->req_exp; exp != NULL; exp = exp->next) { ++ if (exp->action != ACT_SETBE) ++ continue; ++ to = (struct proxy *)exp->replace; ++ propagate_processes(from, to); ++ } ++} ++ + /* + * Returns the error code, 0 if OK, or any combination of : + * - ERR_ABORT: must abort ASAP +@@ -6162,11 +6220,6 @@ int check_config_validity() + } else { + free(curproxy->defbe.name); + curproxy->defbe.be = target; +- /* we force the backend to be present on at least all of +- * the frontend's processes. +- */ +- target->bind_proc = curproxy->bind_proc ? +- (target->bind_proc | curproxy->bind_proc) : 0; + + /* Emit a warning if this proxy also has some servers */ + if (curproxy->srv) { +@@ -6199,11 +6252,6 @@ int check_config_validity() + } else { + free((void *)exp->replace); + exp->replace = (const char *)target; +- /* we force the backend to be present on at least all of +- * the frontend's processes. +- */ +- target->bind_proc = curproxy->bind_proc ? +- (target->bind_proc | curproxy->bind_proc) : 0; + } + } + } +@@ -6252,15 +6300,10 @@ int check_config_validity() + } else { + free((void *)rule->be.name); + rule->be.backend = target; +- /* we force the backend to be present on at least all of +- * the frontend's processes. +- */ +- target->bind_proc = curproxy->bind_proc ? +- (target->bind_proc | curproxy->bind_proc) : 0; + } + } + +- /* find the target proxy for 'use_backend' rules */ ++ /* find the target server for 'use_server' rules */ + list_for_each_entry(srule, &curproxy->server_rules, list) { + struct server *target = findserver(curproxy, srule->srv.name); + +@@ -7131,6 +7174,12 @@ out_uri_auth_compat: + } + } + ++ /* At this point, target names have already been resolved */ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ if (curproxy->cap & PR_CAP_FE) ++ propagate_processes(curproxy, NULL); ++ } ++ + /* automatically compute fullconn if not set. We must not do it in the + * loop above because cross-references are not yet fully resolved. + */ +-- +1.8.4.5 + diff --git a/0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch b/0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch new file mode 100644 index 0000000..82cf146 --- /dev/null +++ b/0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch @@ -0,0 +1,93 @@ +From e56c4f1f76c6731a5a0f4b128540071cffeb1951 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 13:21:03 +0200 +Subject: [PATCH 09/15] MEDIUM: config: make the frontends automatically bind + to the listeners' processes + +When a frontend does not have any bind-process directive, make it +automatically bind to the union of all of its listeners' processes +instead of binding to all processes. That will make it possible to +have the expected behaviour without having to explicitly specify a +bind-process directive. + +Note that if the listeners are not bound to a specific process, the +default is still to bind to all processes. + +This change could be backported to 1.5 as it simplifies process +management, and was planned to be done during the 1.5 development phase. +(cherry picked from commit b369a045d545b41ef2b250bf747caf83c97e0ca8) +--- + doc/configuration.txt | 4 ++++ + src/cfgparse.c | 36 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 40 insertions(+) + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 3c75c92..1e32057 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -1905,6 +1905,10 @@ bind-process [ all | odd | even | [-] ] ... + Each "bind" line may further be limited to a subset of the proxy's processes, + please consult the "process" bind keyword in section 5.1. + ++ When a frontend has no explicit "bind-process" line, it tries to bind to all ++ the processes referenced by its "bind" lines. That means that frontends can ++ easily adapt to their listeners' processes. ++ + If some backends are referenced by frontends bound to other processes, the + backend automatically inherits the frontend's processes. + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index b9853ef..d53f69e 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -7175,11 +7175,47 @@ out_uri_auth_compat: + } + + /* At this point, target names have already been resolved */ ++ ++ /* Make each frontend inherit bind-process from its listeners when not specified. */ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ if (curproxy->bind_proc) ++ continue; ++ ++ list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) { ++ unsigned long mask; ++ ++ mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; ++ curproxy->bind_proc |= mask; ++ } ++ ++ if (!curproxy->bind_proc) ++ curproxy->bind_proc = ~0UL; ++ } ++ ++ if (global.stats_fe) { ++ list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { ++ unsigned long mask; ++ ++ mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; ++ global.stats_fe->bind_proc |= mask; ++ } ++ if (!global.stats_fe->bind_proc) ++ global.stats_fe->bind_proc = ~0UL; ++ } ++ ++ /* propagate bindings from frontends to backends */ + for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + if (curproxy->cap & PR_CAP_FE) + propagate_processes(curproxy, NULL); + } + ++ /* Bind each unbound backend to all processes when not specified. */ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ if (curproxy->bind_proc) ++ continue; ++ curproxy->bind_proc = ~0UL; ++ } ++ + /* automatically compute fullconn if not set. We must not do it in the + * loop above because cross-references are not yet fully resolved. + */ +-- +1.8.4.5 + diff --git a/0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch b/0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch new file mode 100644 index 0000000..63474b9 --- /dev/null +++ b/0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch @@ -0,0 +1,209 @@ +From 91b00c2194b728ccd61133cca83f03de3650b674 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 13:41:21 +0200 +Subject: [PATCH 10/15] MEDIUM: config: compute the exact bind-process before + listener's maxaccept + +This is a continuation of previous patch, the listener's maxaccept is divided +by the number of processes, so it's best if we can swap the two blocks so that +the number of processes is already known when computing the maxaccept value. +(cherry picked from commit 419ead8eca9237f9cc2ec32630d96fde333282ee) +--- + src/cfgparse.c | 156 ++++++++++++++++++++++++++++++--------------------------- + 1 file changed, 81 insertions(+), 75 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index d53f69e..f3907bf 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -6042,12 +6042,11 @@ int check_config_validity() + proxy = next; + } + +- while (curproxy != NULL) { ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { + struct switching_rule *rule; + struct server_rule *srule; + struct sticking_rule *mrule; + struct tcp_rule *trule; +- struct listener *listener; + unsigned int next_id; + int nbproc; + +@@ -6115,14 +6114,6 @@ int check_config_validity() + } + } + +- /* here, if bind_proc is null, it means no limit, otherwise it's explicit. +- * We now check how many processes the proxy will effectively run on. +- */ +- +- nbproc = global.nbproc; +- if (curproxy->bind_proc) +- nbproc = popcount(curproxy->bind_proc & nbits(global.nbproc)); +- + if (global.nbproc > 1 && curproxy->table.peers.name) { + Alert("Proxy '%s': peers can't be used in multi-process mode (nbproc > 1).\n", + curproxy->id); +@@ -7005,6 +6996,86 @@ out_uri_auth_compat: + if (curproxy->options2 & PR_O2_RDPC_PRST) + curproxy->be_req_ana |= AN_REQ_PRST_RDP_COOKIE; + } ++ } ++ ++ /***********************************************************/ ++ /* At this point, target names have already been resolved. */ ++ /***********************************************************/ ++ ++ /* Check multi-process mode compatibility */ ++ ++ if (global.nbproc > 1 && global.stats_fe) { ++ list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { ++ unsigned long mask; ++ ++ mask = nbits(global.nbproc); ++ if (global.stats_fe->bind_proc) ++ mask &= global.stats_fe->bind_proc; ++ ++ if (bind_conf->bind_proc) ++ mask &= bind_conf->bind_proc; ++ ++ /* stop here if more than one process is used */ ++ if (popcount(mask) > 1) ++ break; ++ } ++ if (&bind_conf->by_fe != &global.stats_fe->conf.bind) { ++ Warning("stats socket will not work as expected in multi-process mode (nbproc > 1), you should force process binding globally using 'stats bind-process' or per socket using the 'process' attribute.\n"); ++ } ++ } ++ ++ /* Make each frontend inherit bind-process from its listeners when not specified. */ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ if (curproxy->bind_proc) ++ continue; ++ ++ list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) { ++ unsigned long mask; ++ ++ mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; ++ curproxy->bind_proc |= mask; ++ } ++ ++ if (!curproxy->bind_proc) ++ curproxy->bind_proc = ~0UL; ++ } ++ ++ if (global.stats_fe) { ++ list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { ++ unsigned long mask; ++ ++ mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; ++ global.stats_fe->bind_proc |= mask; ++ } ++ if (!global.stats_fe->bind_proc) ++ global.stats_fe->bind_proc = ~0UL; ++ } ++ ++ /* propagate bindings from frontends to backends */ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ if (curproxy->cap & PR_CAP_FE) ++ propagate_processes(curproxy, NULL); ++ } ++ ++ /* Bind each unbound backend to all processes when not specified. */ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ if (curproxy->bind_proc) ++ continue; ++ curproxy->bind_proc = ~0UL; ++ } ++ ++ /*******************************************************/ ++ /* At this step, all proxies have a non-null bind_proc */ ++ /*******************************************************/ ++ ++ /* perform the final checks before creating tasks */ ++ ++ for (curproxy = proxy; curproxy; curproxy = curproxy->next) { ++ struct listener *listener; ++ unsigned int next_id; ++ int nbproc; ++ ++ nbproc = popcount(curproxy->bind_proc & nbits(global.nbproc)); + + #ifdef USE_OPENSSL + /* Configure SSL for each bind line. +@@ -7149,71 +7220,6 @@ out_uri_auth_compat: + curproxy->id); + cfgerr++; + } +- +- curproxy = curproxy->next; +- } +- +- /* Check multi-process mode compatibility */ +- if (global.nbproc > 1 && global.stats_fe) { +- list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { +- unsigned long mask; +- +- mask = nbits(global.nbproc); +- if (global.stats_fe->bind_proc) +- mask &= global.stats_fe->bind_proc; +- +- if (bind_conf->bind_proc) +- mask &= bind_conf->bind_proc; +- +- /* stop here if more than one process is used */ +- if (popcount(mask) > 1) +- break; +- } +- if (&bind_conf->by_fe != &global.stats_fe->conf.bind) { +- Warning("stats socket will not work as expected in multi-process mode (nbproc > 1), you should force process binding globally using 'stats bind-process' or per socket using the 'process' attribute.\n"); +- } +- } +- +- /* At this point, target names have already been resolved */ +- +- /* Make each frontend inherit bind-process from its listeners when not specified. */ +- for (curproxy = proxy; curproxy; curproxy = curproxy->next) { +- if (curproxy->bind_proc) +- continue; +- +- list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) { +- unsigned long mask; +- +- mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; +- curproxy->bind_proc |= mask; +- } +- +- if (!curproxy->bind_proc) +- curproxy->bind_proc = ~0UL; +- } +- +- if (global.stats_fe) { +- list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { +- unsigned long mask; +- +- mask = bind_conf->bind_proc ? bind_conf->bind_proc : ~0UL; +- global.stats_fe->bind_proc |= mask; +- } +- if (!global.stats_fe->bind_proc) +- global.stats_fe->bind_proc = ~0UL; +- } +- +- /* propagate bindings from frontends to backends */ +- for (curproxy = proxy; curproxy; curproxy = curproxy->next) { +- if (curproxy->cap & PR_CAP_FE) +- propagate_processes(curproxy, NULL); +- } +- +- /* Bind each unbound backend to all processes when not specified. */ +- for (curproxy = proxy; curproxy; curproxy = curproxy->next) { +- if (curproxy->bind_proc) +- continue; +- curproxy->bind_proc = ~0UL; + } + + /* automatically compute fullconn if not set. We must not do it in the +-- +1.8.4.5 + diff --git a/0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch b/0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch new file mode 100644 index 0000000..fbb324f --- /dev/null +++ b/0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch @@ -0,0 +1,45 @@ +From 036a83e9c300a42386cd378022420e52a43b314f Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 15:11:04 +0200 +Subject: [PATCH 11/15] MEDIUM: config: only warn if stats are attached to + multi-process bind directives + +Some users want to have a stats frontend with one line per process, but while +100% valid and safe, the config parser emits a warning. Relax this check to +ensure that the warning is only emitted if at least one of the listeners is +bound to multiple processes, or if the directive is placed in a backend called +from multiple processes (since in this case we don't know if it's safe). +(cherry picked from commit eb791e03b5c5abfddb24a439fa6434788db026b7) +--- + src/cfgparse.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index f3907bf..5668393 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -7189,8 +7189,19 @@ out_uri_auth_compat: + + if (nbproc > 1) { + if (curproxy->uri_auth) { +- Warning("Proxy '%s': in multi-process mode, stats will be limited to process assigned to the current request.\n", +- curproxy->id); ++ int count, maxproc = 0; ++ ++ list_for_each_entry(bind_conf, &curproxy->conf.bind, by_fe) { ++ count = popcount(bind_conf->bind_proc); ++ if (count > maxproc) ++ maxproc = count; ++ } ++ /* backends have 0, frontends have 1 or more */ ++ if (maxproc != 1) ++ Warning("Proxy '%s': in multi-process mode, stats will be" ++ " limited to process assigned to the current request.\n", ++ curproxy->id); ++ + if (!LIST_ISEMPTY(&curproxy->uri_auth->admin_rules)) { + Warning("Proxy '%s': stats admin will not work correctly in multi-process mode.\n", + curproxy->id); +-- +1.8.4.5 + diff --git a/0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch b/0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch new file mode 100644 index 0000000..1be39b1 --- /dev/null +++ b/0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch @@ -0,0 +1,110 @@ +From 8b3c808c37dd5672f87e7b61085295e1316a6694 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 15:39:51 +0200 +Subject: [PATCH 12/15] MEDIUM: config: report it when tcp-request rules are + misplaced + +A config where a tcp-request rule appears after an http-request rule +might seem valid but it is not. So let's report a warning about this +since this case is hard to detect by the naked eye. +(cherry picked from commit 3986b9c14037f446f5f5bec6207a39e1bd753fae) +--- + include/common/cfgparse.h | 2 ++ + src/cfgparse.c | 38 ++++++++++++++++++++++++++++++++++++++ + src/proto_tcp.c | 4 ++++ + 3 files changed, 44 insertions(+) + +diff --git a/include/common/cfgparse.h b/include/common/cfgparse.h +index 80310ae..86a0035 100644 +--- a/include/common/cfgparse.h ++++ b/include/common/cfgparse.h +@@ -73,6 +73,8 @@ int check_config_validity(); + int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, const char *file, int line, char **err); + int cfg_register_section(char *section_name, + int (*section_parser)(const char *, int, char **, int)); ++int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg); ++int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg); + + /* + * Sends a warning if proxy does not have at least one of the +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 5668393..9ff44e9 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -317,6 +317,19 @@ int str2listener(char *str, struct proxy *curproxy, struct bind_conf *bind_conf, + return 0; + } + ++/* Report a warning if a rule is placed after a 'tcp-request content' rule. ++ * Return 1 if the warning has been emitted, otherwise 0. ++ */ ++int warnif_rule_after_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg) ++{ ++ if (!LIST_ISEMPTY(&proxy->tcp_req.inspect_rules)) { ++ Warning("parsing [%s:%d] : a '%s' rule placed after a 'tcp-request content' rule will still be processed before.\n", ++ file, line, arg); ++ return 1; ++ } ++ return 0; ++} ++ + /* Report a warning if a rule is placed after a 'block' rule. + * Return 1 if the warning has been emitted, otherwise 0. + */ +@@ -408,6 +421,31 @@ int warnif_rule_after_use_server(struct proxy *proxy, const char *file, int line + return 0; + } + ++/* report a warning if a "tcp request connection" rule is dangerously placed */ ++int warnif_misplaced_tcp_conn(struct proxy *proxy, const char *file, int line, const char *arg) ++{ ++ return warnif_rule_after_tcp_cont(proxy, file, line, arg) || ++ warnif_rule_after_block(proxy, file, line, arg) || ++ warnif_rule_after_http_req(proxy, file, line, arg) || ++ warnif_rule_after_reqxxx(proxy, file, line, arg) || ++ warnif_rule_after_reqadd(proxy, file, line, arg) || ++ warnif_rule_after_redirect(proxy, file, line, arg) || ++ warnif_rule_after_use_backend(proxy, file, line, arg) || ++ warnif_rule_after_use_server(proxy, file, line, arg); ++} ++ ++/* report a warning if a "tcp request content" rule is dangerously placed */ ++int warnif_misplaced_tcp_cont(struct proxy *proxy, const char *file, int line, const char *arg) ++{ ++ return warnif_rule_after_block(proxy, file, line, arg) || ++ warnif_rule_after_http_req(proxy, file, line, arg) || ++ warnif_rule_after_reqxxx(proxy, file, line, arg) || ++ warnif_rule_after_reqadd(proxy, file, line, arg) || ++ warnif_rule_after_redirect(proxy, file, line, arg) || ++ warnif_rule_after_use_backend(proxy, file, line, arg) || ++ warnif_rule_after_use_server(proxy, file, line, arg); ++} ++ + /* report a warning if a block rule is dangerously placed */ + int warnif_misplaced_block(struct proxy *proxy, const char *file, int line, const char *arg) + { +diff --git a/src/proto_tcp.c b/src/proto_tcp.c +index 72dc92b..940c3f1 100644 +--- a/src/proto_tcp.c ++++ b/src/proto_tcp.c +@@ -1711,6 +1711,8 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx, + warn++; + } + ++ /* the following function directly emits the warning */ ++ warnif_misplaced_tcp_cont(curpx, file, line, args[0]); + LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list); + } + else if (strcmp(args[1], "connection") == 0) { +@@ -1754,6 +1756,8 @@ static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx, + warn++; + } + ++ /* the following function directly emits the warning */ ++ warnif_misplaced_tcp_conn(curpx, file, line, args[0]); + LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list); + } + else { +-- +1.8.4.5 + diff --git a/0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch b/0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch new file mode 100644 index 0000000..e83e56c --- /dev/null +++ b/0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch @@ -0,0 +1,52 @@ +From 7fc7ebd5785629074297ee324b22e0aee9ad00f9 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Tue, 16 Sep 2014 16:21:19 +0200 +Subject: [PATCH 13/15] MINOR: config: detect the case where a tcp-request + content rule has no inspect-delay + +If a frontend has any tcp-request content rule relying on request contents +without any inspect delay, we now emit a warning as this will randomly match. + +This can be backported to 1.5 as it reduces the support effort. +(cherry picked from commit e42bd96d0acc38ea7c546c8de8115ffd1dd6c3f3) +--- + src/cfgparse.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 9ff44e9..f723a3a 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -6998,6 +6998,29 @@ out_uri_auth_compat: + newsrv = newsrv->next; + } + ++ /* check if we have a frontend with "tcp-request content" looking at L7 ++ * with no inspect-delay ++ */ ++ if ((curproxy->cap & PR_CAP_FE) && !curproxy->tcp_req.inspect_delay) { ++ list_for_each_entry(trule, &curproxy->tcp_req.inspect_rules, list) { ++ if (trule->action == TCP_ACT_CAPTURE && ++ !(trule->act_prm.cap.expr->fetch->val & SMP_VAL_FE_SES_ACC)) ++ break; ++ if ((trule->action >= TCP_ACT_TRK_SC0 && trule->action <= TCP_ACT_TRK_SCMAX) && ++ !(trule->act_prm.trk_ctr.expr->fetch->val & SMP_VAL_FE_SES_ACC)) ++ break; ++ } ++ ++ if (&trule->list != &curproxy->tcp_req.inspect_rules) { ++ Warning("config : %s '%s' : some 'tcp-request content' rules explicitly depending on request" ++ " contents were found in a frontend without any 'tcp-request inspect-delay' setting." ++ " This means that these rules will randomly find their contents. This can be fixed by" ++ " setting the tcp-request inspect-delay.\n", ++ proxy_type_str(curproxy), curproxy->id); ++ err_code |= ERR_WARN; ++ } ++ } ++ + if (curproxy->cap & PR_CAP_FE) { + if (!curproxy->accept) + curproxy->accept = frontend_accept; +-- +1.8.4.5 + diff --git a/0014-MEDIUM-systemd-wrapper-support-multiple-executable-v.patch b/0014-MEDIUM-systemd-wrapper-support-multiple-executable-v.patch new file mode 100644 index 0000000..ffc96eb --- /dev/null +++ b/0014-MEDIUM-systemd-wrapper-support-multiple-executable-v.patch @@ -0,0 +1,90 @@ +From afbfc27c0f2cac29e18f87b36335ea821c633b9d Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Fri, 19 Sep 2014 15:42:30 +0200 +Subject: [PATCH 14/15] MEDIUM: systemd-wrapper: support multiple executable + versions and names + +Having to use a hard-coded "haproxy" executable name next to the systemd +wrapper is not always convenient, as it's sometimes desirable to run with +multiple versions in parallel. + +Thus this patch performs a minor change to the wrapper : if the name ends +with "-systemd-wrapper", then it trims that part off and what remains +becomes the target haproxy executable. That makes it easy to have for +example : + + haproxy-1.5.4-systemd-wrapper haproxy-1.5.4 + haproxy-1.5.3-systemd-wrapper haproxy-1.5.3 + +and so on, in a same directory. + +This patch also fixes a rare bug caused by readlink() not adding the +trailing zero and leaving possible existing contents, including possibly +a randomly placed "/" which would make it unable to locate the correct +binary. This case is not totally unlikely as I got a \177 a few times +at the end of the executable names, so I could have got a '/' as well. + +Back-porting to 1.5 is desirable. +(cherry picked from commit ceaf2aec1ec1612da461c61798e944693144bee9) +--- + src/haproxy-systemd-wrapper.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c +index cc8baa8..446f28f 100644 +--- a/src/haproxy-systemd-wrapper.c ++++ b/src/haproxy-systemd-wrapper.c +@@ -28,20 +28,36 @@ static char *pid_file = "/run/haproxy.pid"; + static int wrapper_argc; + static char **wrapper_argv; + ++/* returns the path to the haproxy binary into , whose size indicated ++ * in must be at least 1 byte long. ++ */ + static void locate_haproxy(char *buffer, size_t buffer_size) + { + char *end = NULL; ++ int len; + +- if (readlink("/proc/self/exe", buffer, buffer_size) > 0) +- end = strrchr(buffer, '/'); ++ len = readlink("/proc/self/exe", buffer, buffer_size - 1); ++ if (len == -1) ++ goto fail; + +- if (end == NULL) { +- strncpy(buffer, "/usr/sbin/haproxy", buffer_size); ++ buffer[len] = 0; ++ end = strrchr(buffer, '/'); ++ if (end == NULL) ++ goto fail; ++ ++ if (strcmp(end + strlen(end) - 16, "-systemd-wrapper") == 0) { ++ end[strlen(end) - 16] = '\0'; + return; + } ++ + end[1] = '\0'; + strncpy(end + 1, "haproxy", buffer + buffer_size - (end + 1)); + buffer[buffer_size - 1] = '\0'; ++ return; ++ fail: ++ strncpy(buffer, "/usr/sbin/haproxy", buffer_size); ++ buffer[buffer_size - 1] = '\0'; ++ return; + } + + static void spawn_haproxy(char **pid_strv, int nb_pid) +@@ -54,7 +70,8 @@ static void spawn_haproxy(char **pid_strv, int nb_pid) + main_argc = wrapper_argc - 1; + main_argv = wrapper_argv + 1; + +- pid = fork(); ++ //pid = fork(); ++ pid=0; + if (!pid) { + /* 3 for "haproxy -Ds -sf" */ + char **argv = calloc(4 + main_argc + nb_pid + 1, sizeof(char *)); +-- +1.8.4.5 + diff --git a/0015-BUG-MEDIUM-remove-debugging-code-from-systemd-wrappe.patch b/0015-BUG-MEDIUM-remove-debugging-code-from-systemd-wrappe.patch new file mode 100644 index 0000000..6468c23 --- /dev/null +++ b/0015-BUG-MEDIUM-remove-debugging-code-from-systemd-wrappe.patch @@ -0,0 +1,36 @@ +From 575e299cc07f5f2b314d91dfac8671834cbdd2a7 Mon Sep 17 00:00:00 2001 +From: Willy Tarreau +Date: Wed, 24 Sep 2014 12:59:25 +0200 +Subject: [PATCH 15/15] BUG/MEDIUM: remove debugging code from systemd-wrapper +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Kristoffer Grönlund reported that after my recent update to the +systemd-wrapper, I accidentely left the debugging code which +consists in disabling the fork :-( + +The fix needs to be backported to 1.5 as well since I pushed it +there as well. +(cherry picked from commit a55bbc64d8272e4066a67b6d190ffebaff2b300a) +--- + src/haproxy-systemd-wrapper.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/haproxy-systemd-wrapper.c b/src/haproxy-systemd-wrapper.c +index 446f28f..8602881 100644 +--- a/src/haproxy-systemd-wrapper.c ++++ b/src/haproxy-systemd-wrapper.c +@@ -70,8 +70,7 @@ static void spawn_haproxy(char **pid_strv, int nb_pid) + main_argc = wrapper_argc - 1; + main_argv = wrapper_argv + 1; + +- //pid = fork(); +- pid=0; ++ pid = fork(); + if (!pid) { + /* 3 for "haproxy -Ds -sf" */ + char **argv = calloc(4 + main_argc + nb_pid + 1, sizeof(char *)); +-- +1.8.4.5 + diff --git a/haproxy.changes b/haproxy.changes index 68e2426..8a89eef 100644 --- a/haproxy.changes +++ b/haproxy.changes @@ -1,7 +1,44 @@ +------------------------------------------------------------------- +Thu Sep 25 16:10:08 UTC 2014 - kgronlund@suse.com + +- Backported fixes (bnc#898498): + - DOC: clearly state that the "show sess" output format is not fixed + - MINOR: stats: fix minor typo fix in stats_dump_errors_to_buffer() + - MEDIUM: Improve signal handling in systemd wrapper. + - MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper + - DOC: indicate in the doc that track-sc* can wait if data are missing + - MEDIUM: http: enable header manipulation for 101 responses + - BUG/MEDIUM: config: propagate frontend to backend process binding again. + - MEDIUM: config: properly propagate process binding between proxies + - MEDIUM: config: make the frontends automatically bind to the listeners' processes + - MEDIUM: config: compute the exact bind-process before listener's maxaccept + - MEDIUM: config: only warn if stats are attached to multi-process bind directives + - MEDIUM: config: report it when tcp-request rules are misplaced + - MINOR: config: detect the case where a tcp-request content rule has no inspect-delay + - MEDIUM: systemd-wrapper: support multiple executable versions and names + - BUG/MEDIUM: remove debugging code from systemd-wrapper + +- Added patches: + - 0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch + - 0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch + - 0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch + - 0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch + - 0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch + - 0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch + - 0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch + - 0008-MEDIUM-config-properly-propagate-process-binding-bet.patch + - 0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch + - 0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch + - 0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch + - 0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch + - 0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch + - 0014-MEDIUM-systemd-wrapper-support-multiple-executable-v.patch + - 0015-BUG-MEDIUM-remove-debugging-code-from-systemd-wrappe.patch + ------------------------------------------------------------------- Wed Sep 3 07:35:14 UTC 2014 - kgronlund@suse.com -- update to 1.5.4 +- update to 1.5.4 (bnc#895849 CVE-2014-6269) - BUG: config: error in http-response replace-header number of arguments - BUG/MINOR: Fix search for -p argument in systemd wrapper. - BUG/MEDIUM: auth: fix segfault with http-auth and a configuration with an unknown encryption algorithm diff --git a/haproxy.spec b/haproxy.spec index 36d37bc..24d530a 100644 --- a/haproxy.spec +++ b/haproxy.spec @@ -61,6 +61,36 @@ Patch1: haproxy-1.2.16_config_haproxy_user.patch Patch2: haproxy-makefile_lib.patch Patch3: sec-options.patch Patch4: haproxy-1.5_check_config_before_start.patch +# PATCH-FIX-UPSTREAM: DOC: clearly state that the "show sess" output format is not fixed +Patch5: 0001-DOC-clearly-state-that-the-show-sess-output-format-i.patch +# PATCH-FIX-UPSTREAM: MINOR: stats: fix minor typo fix in stats_dump_errors_to_buffer() +Patch6: 0002-MINOR-stats-fix-minor-typo-fix-in-stats_dump_errors_.patch +# PATCH-FIX-UPSTREAM: MEDIUM: Improve signal handling in systemd wrapper. +Patch7: 0003-MEDIUM-Improve-signal-handling-in-systemd-wrapper.patch +# PATCH-FIX-UPSTREAM: MINOR: Also accept SIGHUP/SIGTERM in systemd-wrapper +Patch8: 0004-MINOR-Also-accept-SIGHUP-SIGTERM-in-systemd-wrapper.patch +# PATCH-FIX-UPSTREAM: DOC: indicate in the doc that track-sc* can wait if data are missing +Patch9: 0005-DOC-indicate-in-the-doc-that-track-sc-can-wait-if-da.patch +# PATCH-FIX-UPSTREAM: MEDIUM: http: enable header manipulation for 101 responses +Patch10: 0006-MEDIUM-http-enable-header-manipulation-for-101-respo.patch +# PATCH-FIX-UPSTREAM: BUG/MEDIUM: config: propagate frontend to backend process binding again. +Patch11: 0007-BUG-MEDIUM-config-propagate-frontend-to-backend-proc.patch +# PATCH-FIX-UPSTREAM: MEDIUM: config: properly propagate process binding between proxies +Patch12: 0008-MEDIUM-config-properly-propagate-process-binding-bet.patch +# PATCH-FIX-UPSTREAM: MEDIUM: config: make the frontends automatically bind to the listeners' processes +Patch13: 0009-MEDIUM-config-make-the-frontends-automatically-bind-.patch +# PATCH-FIX-UPSTREAM: MEDIUM: config: compute the exact bind-process before listener's maxaccept +Patch14: 0010-MEDIUM-config-compute-the-exact-bind-process-before-.patch +# PATCH-FIX-UPSTREAM: MEDIUM: config: only warn if stats are attached to multi-process bind directives +Patch15: 0011-MEDIUM-config-only-warn-if-stats-are-attached-to-mul.patch +# PATCH-FIX-UPSTREAM: MEDIUM: config: report it when tcp-request rules are misplaced +Patch16: 0012-MEDIUM-config-report-it-when-tcp-request-rules-are-m.patch +# PATCH-FIX-UPSTREAM: MINOR: config: detect the case where a tcp-request content rule has no inspect-delay +Patch17: 0013-MINOR-config-detect-the-case-where-a-tcp-request-con.patch +# PATCH-FIX-UPSTREAM: MEDIUM: systemd-wrapper: support multiple executable versions and names +Patch18: 0014-MEDIUM-systemd-wrapper-support-multiple-executable-v.patch +# PATCH-FIX-UPSTREAM: BUG/MEDIUM: remove debugging code from systemd-wrapper +Patch19: 0015-BUG-MEDIUM-remove-debugging-code-from-systemd-wrappe.patch Source99: haproxy-rpmlintrc # Summary: The Reliable, High Performance TCP/HTTP Load Balancer @@ -94,6 +124,21 @@ the most work done from every CPU cycle. %patch2 %patch3 %patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 %build %{__make} \