1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
commit fac50825151ac2abc6b71343e3ffa6e0dc06c53d
Author: Christopher Faulet <cfaulet@haproxy.com>
Date: Tue Jan 21 11:06:48 2020 +0100
MINOR: proxy/http-ana: Add support of extra attributes for the cookie directive
It is now possible to insert any attribute when a cookie is inserted by
HAProxy. Any value may be set, no check is performed except the syntax validity
(CTRL chars and ';' are forbidden). For instance, it may be used to add the
SameSite attribute:
cookie SRV insert attr "SameSite=Strict"
The attr option may be repeated to add several attributes.
This patch should fix the issue #361.
(cherry picked from commit 2f5339079b884ac8bdde166add1879ebfd9e433b)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 3f381e386..e0dc49880 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -3255,7 +3255,7 @@ compression offload
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
[ postonly ] [ preserve ] [ httponly ] [ secure ]
[ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
- [ dynamic ]
+ [ dynamic ] [ attr <value> ]*
Enable cookie-based persistence in a backend.
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
@@ -3414,6 +3414,11 @@ cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
The cookie will be regenerated each time the IP address change,
and is only generated for IPv4/IPv6.
+ attr This option tells haproxy to add an extra attribute when a
+ cookie is inserted. The attribute value can contain any
+ characters except control ones or ";". This option may be
+ repeated.
+
There can be only one persistence cookie per HTTP backend, and it can be
declared in a defaults section. The value of the cookie will be the value
indicated after the "cookie" keyword in a "server" statement. If no cookie
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 6ea96b3ad..3661c9a0c 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -338,6 +338,7 @@ struct proxy {
int cookie_len; /* strlen(cookie_name), computed only once */
char *cookie_domain; /* domain used to insert the cookie */
char *cookie_name; /* name of the cookie to look for */
+ char *cookie_attrs; /* list of attributes to add to the cookie */
char *dyncookie_key; /* Secret key used to generate dynamic persistent cookies */
unsigned int cookie_maxidle; /* max idle time for this cookie */
unsigned int cookie_maxlife; /* max life time for this cookie */
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index 9975e4687..b1f5c0790 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -323,6 +323,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
curproxy->rdp_cookie_name = strdup(defproxy.rdp_cookie_name);
curproxy->rdp_cookie_len = defproxy.rdp_cookie_len;
+ if (defproxy.cookie_attrs)
+ curproxy->cookie_attrs = strdup(defproxy.cookie_attrs);
if (defproxy.lbprm.arg_str)
curproxy->lbprm.arg_str = strdup(defproxy.lbprm.arg_str);
@@ -473,6 +475,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
free(defproxy.rdp_cookie_name);
free(defproxy.dyncookie_key);
free(defproxy.cookie_domain);
+ free(defproxy.cookie_attrs);
free(defproxy.lbprm.arg_str);
free(defproxy.capture_name);
free(defproxy.monitor_uri);
@@ -986,9 +989,34 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
err_code |= ERR_WARN;
curproxy->ck_opts |= PR_CK_DYNAMIC;
}
+ else if (!strcmp(args[cur_arg], "attr")) {
+ char *val;
+ if (!*args[cur_arg + 1]) {
+ ha_alert("parsing [%s:%d]: '%s' expects <value> as argument.\n",
+ file, linenum, args[cur_arg]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ val = args[cur_arg + 1];
+ while (*val) {
+ if (iscntrl(*val) || *val == ';') {
+ ha_alert("parsing [%s:%d]: character '%%x%02X' is not permitted in attribute value.\n",
+ file, linenum, *val);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ val++;
+ }
+ /* don't add ';' for the first attribute */
+ if (!curproxy->cookie_attrs)
+ curproxy->cookie_attrs = strdup(args[cur_arg + 1]);
+ else
+ memprintf(&curproxy->cookie_attrs, "%s; %s", curproxy->cookie_attrs, args[cur_arg + 1]);
+ cur_arg++;
+ }
else {
- ha_alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache', 'postonly', 'domain', 'maxidle', 'dynamic' and 'maxlife' options.\n",
+ ha_alert("parsing [%s:%d] : '%s' supports 'rewrite', 'insert', 'prefix', 'indirect', 'nocache', 'postonly', 'domain', 'maxidle', 'dynamic', 'maxlife' and 'attr' options.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
diff --git a/src/haproxy.c b/src/haproxy.c
index f225a13f8..98d6a9a39 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -2352,6 +2352,7 @@ void deinit(void)
free(p->check_req);
free(p->cookie_name);
free(p->cookie_domain);
+ free(p->cookie_attrs);
free(p->lbprm.arg_str);
free(p->capture_name);
free(p->monitor_uri);
diff --git a/src/http_ana.c b/src/http_ana.c
index 047ed813a..cb5a60ca9 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -2027,6 +2027,9 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
if (s->be->ck_opts & PR_CK_SECURE)
chunk_appendf(&trash, "; Secure");
+ if (s->be->cookie_attrs)
+ chunk_appendf(&trash, "; %s", s->be->cookie_attrs);
+
if (unlikely(!http_add_header(htx, ist("Set-Cookie"), ist2(trash.area, trash.data))))
goto return_bad_resp;
|