1 /*
2  * "tcp" rules processing
3  *
4  * Copyright 2000-2016 Willy Tarreau <w@1wt.eu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  *
11  */
12 #include <common/cfgparse.h>
13 #include <common/compat.h>
14 #include <common/config.h>
15 #include <common/debug.h>
16 #include <common/initcall.h>
17 #include <common/mini-clist.h>
18 #include <common/standard.h>
19 #include <common/ticks.h>
20 #include <common/time.h>
21 
22 #include <types/arg.h>
23 #include <types/capture.h>
24 #include <types/connection.h>
25 #include <types/global.h>
26 
27 #include <proto/acl.h>
28 #include <proto/action.h>
29 #include <proto/channel.h>
30 #include <proto/connection.h>
31 #include <proto/log.h>
32 #include <proto/proxy.h>
33 #include <proto/sample.h>
34 #include <proto/stick_table.h>
35 #include <proto/stream.h>
36 #include <proto/stream_interface.h>
37 #include <proto/tcp_rules.h>
38 
39 #define TRACE_SOURCE &trace_strm
40 
41 /* List head of all known action keywords for "tcp-request connection" */
42 struct list tcp_req_conn_keywords = LIST_HEAD_INIT(tcp_req_conn_keywords);
43 struct list tcp_req_sess_keywords = LIST_HEAD_INIT(tcp_req_sess_keywords);
44 struct list tcp_req_cont_keywords = LIST_HEAD_INIT(tcp_req_cont_keywords);
45 struct list tcp_res_cont_keywords = LIST_HEAD_INIT(tcp_res_cont_keywords);
46 
47 /*
48  * Register keywords.
49  */
tcp_req_conn_keywords_register(struct action_kw_list * kw_list)50 void tcp_req_conn_keywords_register(struct action_kw_list *kw_list)
51 {
52 	LIST_ADDQ(&tcp_req_conn_keywords, &kw_list->list);
53 }
54 
tcp_req_sess_keywords_register(struct action_kw_list * kw_list)55 void tcp_req_sess_keywords_register(struct action_kw_list *kw_list)
56 {
57 	LIST_ADDQ(&tcp_req_sess_keywords, &kw_list->list);
58 }
59 
tcp_req_cont_keywords_register(struct action_kw_list * kw_list)60 void tcp_req_cont_keywords_register(struct action_kw_list *kw_list)
61 {
62 	LIST_ADDQ(&tcp_req_cont_keywords, &kw_list->list);
63 }
64 
tcp_res_cont_keywords_register(struct action_kw_list * kw_list)65 void tcp_res_cont_keywords_register(struct action_kw_list *kw_list)
66 {
67 	LIST_ADDQ(&tcp_res_cont_keywords, &kw_list->list);
68 }
69 
70 /*
71  * Return the struct tcp_req_action_kw associated to a keyword.
72  */
tcp_req_conn_action(const char * kw)73 static struct action_kw *tcp_req_conn_action(const char *kw)
74 {
75 	return action_lookup(&tcp_req_conn_keywords, kw);
76 }
77 
tcp_req_sess_action(const char * kw)78 static struct action_kw *tcp_req_sess_action(const char *kw)
79 {
80 	return action_lookup(&tcp_req_sess_keywords, kw);
81 }
82 
tcp_req_cont_action(const char * kw)83 static struct action_kw *tcp_req_cont_action(const char *kw)
84 {
85 	return action_lookup(&tcp_req_cont_keywords, kw);
86 }
87 
tcp_res_cont_action(const char * kw)88 static struct action_kw *tcp_res_cont_action(const char *kw)
89 {
90 	return action_lookup(&tcp_res_cont_keywords, kw);
91 }
92 
93 /* This function performs the TCP request analysis on the current request. It
94  * returns 1 if the processing can continue on next analysers, or zero if it
95  * needs more data, encounters an error, or wants to immediately abort the
96  * request. It relies on buffers flags, and updates s->req->analysers. The
97  * function may be called for frontend rules and backend rules. It only relies
98  * on the backend pointer so this works for both cases.
99  */
tcp_inspect_request(struct stream * s,struct channel * req,int an_bit)100 int tcp_inspect_request(struct stream *s, struct channel *req, int an_bit)
101 {
102 	struct session *sess = s->sess;
103 	struct act_rule *rule;
104 	struct stksess *ts;
105 	struct stktable *t;
106 	int partial;
107 	int act_flags = 0;
108 
109 	DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
110 
111 	/* We don't know whether we have enough data, so must proceed
112 	 * this way :
113 	 * - iterate through all rules in their declaration order
114 	 * - if one rule returns MISS, it means the inspect delay is
115 	 *   not over yet, then return immediately, otherwise consider
116 	 *   it as a non-match.
117 	 * - if one rule returns OK, then return OK
118 	 * - if one rule returns KO, then return KO
119 	 */
120 
121 	if ((req->flags & CF_SHUTR) || channel_full(req, global.tune.maxrewrite) ||
122 	    !s->be->tcp_req.inspect_delay || tick_is_expired(req->analyse_exp, now_ms))
123 		partial = SMP_OPT_FINAL;
124 	else
125 		partial = 0;
126 
127 	/* If "the current_rule_list" match the executed rule list, we are in
128 	 * resume condition. If a resume is needed it is always in the action
129 	 * and never in the ACL or converters. In this case, we initialise the
130 	 * current rule, and go to the action execution point.
131 	 */
132 	if (s->current_rule) {
133 		rule = s->current_rule;
134 		s->current_rule = NULL;
135 		if (s->current_rule_list == &s->be->tcp_req.inspect_rules)
136 			goto resume_execution;
137 	}
138 	s->current_rule_list = &s->be->tcp_req.inspect_rules;
139 
140 	list_for_each_entry(rule, &s->be->tcp_req.inspect_rules, list) {
141 		enum acl_test_res ret = ACL_TEST_PASS;
142 
143 		if (rule->cond) {
144 			ret = acl_exec_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_REQ | partial);
145 			if (ret == ACL_TEST_MISS)
146 				goto missing_data;
147 
148 			ret = acl_pass(ret);
149 			if (rule->cond->pol == ACL_COND_UNLESS)
150 				ret = !ret;
151 		}
152 
153 		if (ret) {
154 			act_flags |= ACT_FLAG_FIRST;
155 resume_execution:
156 			/* we have a matching rule. */
157 			if (rule->action == ACT_ACTION_ALLOW) {
158 				break;
159 			}
160 			else if (rule->action == ACT_ACTION_DENY) {
161 				si_must_kill_conn(chn_prod(req));
162 				channel_abort(req);
163 				channel_abort(&s->res);
164 				req->analysers = 0;
165 
166 				_HA_ATOMIC_ADD(&s->be->be_counters.denied_req, 1);
167 				_HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_req, 1);
168 				if (sess->listener && sess->listener->counters)
169 					_HA_ATOMIC_ADD(&sess->listener->counters->denied_req, 1);
170 
171 				if (!(s->flags & SF_ERR_MASK))
172 					s->flags |= SF_ERR_PRXCOND;
173 				if (!(s->flags & SF_FINST_MASK))
174 					s->flags |= SF_FINST_R;
175 				DBG_TRACE_DEVEL("leaving on error", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA|STRM_EV_TCP_ERR, s);
176 				return 0;
177 			}
178 			else if (rule->action >= ACT_ACTION_TRK_SC0 && rule->action <= ACT_ACTION_TRK_SCMAX) {
179 				/* Note: only the first valid tracking parameter of each
180 				 * applies.
181 				 */
182 				struct stktable_key *key;
183 				struct sample smp;
184 
185 				if (stkctr_entry(&s->stkctr[trk_idx(rule->action)]))
186 					continue;
187 
188 				t = rule->arg.trk_ctr.table.t;
189 				key = stktable_fetch_key(t, s->be, sess, s, SMP_OPT_DIR_REQ | partial, rule->arg.trk_ctr.expr, &smp);
190 
191 				if ((smp.flags & SMP_F_MAY_CHANGE) && !(partial & SMP_OPT_FINAL))
192 					goto missing_data; /* key might appear later */
193 
194 				if (key && (ts = stktable_get_entry(t, key))) {
195 					stream_track_stkctr(&s->stkctr[trk_idx(rule->action)], t, ts);
196 					stkctr_set_flags(&s->stkctr[trk_idx(rule->action)], STKCTR_TRACK_CONTENT);
197 					if (sess->fe != s->be)
198 						stkctr_set_flags(&s->stkctr[trk_idx(rule->action)], STKCTR_TRACK_BACKEND);
199 				}
200 			}
201 			else if (rule->action == ACT_TCP_CAPTURE) {
202 				struct sample *key;
203 				struct cap_hdr *h = rule->arg.cap.hdr;
204 				char **cap = s->req_cap;
205 				int len;
206 
207 				key = sample_fetch_as_type(s->be, sess, s, SMP_OPT_DIR_REQ | partial, rule->arg.cap.expr, SMP_T_STR);
208 				if (!key)
209 					continue;
210 
211 				if (key->flags & SMP_F_MAY_CHANGE)
212 					goto missing_data;
213 
214 				if (cap[h->index] == NULL)
215 					cap[h->index] = pool_alloc(h->pool);
216 
217 				if (cap[h->index] == NULL) /* no more capture memory */
218 					continue;
219 
220 				len = key->data.u.str.data;
221 				if (len > h->len)
222 					len = h->len;
223 
224 				memcpy(cap[h->index], key->data.u.str.area,
225 				       len);
226 				cap[h->index][len] = 0;
227 			}
228 			else {
229 				/* Custom keywords. */
230 				if (!rule->action_ptr)
231 					continue;
232 
233 				if (partial & SMP_OPT_FINAL)
234 					act_flags |= ACT_FLAG_FINAL;
235 
236 				switch (rule->action_ptr(rule, s->be, s->sess, s, act_flags)) {
237 				case ACT_RET_ERR:
238 				case ACT_RET_CONT:
239 					continue;
240 				case ACT_RET_STOP:
241 				case ACT_RET_DONE:
242 					break;
243 				case ACT_RET_YIELD:
244 					s->current_rule = rule;
245 					goto missing_data;
246 				}
247 				break; /* ACT_RET_STOP/DONE */
248 			}
249 		}
250 	}
251 
252 	/* if we get there, it means we have no rule which matches, or
253 	 * we have an explicit accept, so we apply the default accept.
254 	 */
255 	req->analysers &= ~an_bit;
256 	req->analyse_exp = TICK_ETERNITY;
257 	DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
258 	return 1;
259 
260  missing_data:
261 	channel_dont_connect(req);
262 	/* just set the request timeout once at the beginning of the request */
263 	if (!tick_isset(req->analyse_exp) && s->be->tcp_req.inspect_delay)
264 		req->analyse_exp = tick_add(now_ms, s->be->tcp_req.inspect_delay);
265 	DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
266 	return 0;
267 
268 }
269 
270 /* This function performs the TCP response analysis on the current response. It
271  * returns 1 if the processing can continue on next analysers, or zero if it
272  * needs more data, encounters an error, or wants to immediately abort the
273  * response. It relies on buffers flags, and updates s->rep->analysers. The
274  * function may be called for backend rules.
275  */
tcp_inspect_response(struct stream * s,struct channel * rep,int an_bit)276 int tcp_inspect_response(struct stream *s, struct channel *rep, int an_bit)
277 {
278 	struct session *sess = s->sess;
279 	struct act_rule *rule;
280 	int partial;
281 	int act_flags = 0;
282 
283 	DBG_TRACE_ENTER(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
284 
285 	/* We don't know whether we have enough data, so must proceed
286 	 * this way :
287 	 * - iterate through all rules in their declaration order
288 	 * - if one rule returns MISS, it means the inspect delay is
289 	 *   not over yet, then return immediately, otherwise consider
290 	 *   it as a non-match.
291 	 * - if one rule returns OK, then return OK
292 	 * - if one rule returns KO, then return KO
293 	 */
294 
295 	if (rep->flags & CF_SHUTR || tick_is_expired(rep->analyse_exp, now_ms))
296 		partial = SMP_OPT_FINAL;
297 	else
298 		partial = 0;
299 
300 	/* If "the current_rule_list" match the executed rule list, we are in
301 	 * resume condition. If a resume is needed it is always in the action
302 	 * and never in the ACL or converters. In this case, we initialise the
303 	 * current rule, and go to the action execution point.
304 	 */
305 	if (s->current_rule) {
306 		rule = s->current_rule;
307 		s->current_rule = NULL;
308 		if (s->current_rule_list == &s->be->tcp_rep.inspect_rules)
309 			goto resume_execution;
310 	}
311 	s->current_rule_list = &s->be->tcp_rep.inspect_rules;
312 
313 	list_for_each_entry(rule, &s->be->tcp_rep.inspect_rules, list) {
314 		enum acl_test_res ret = ACL_TEST_PASS;
315 
316 		if (rule->cond) {
317 			ret = acl_exec_cond(rule->cond, s->be, sess, s, SMP_OPT_DIR_RES | partial);
318 			if (ret == ACL_TEST_MISS) {
319 				/* just set the analyser timeout once at the beginning of the response */
320 				if (!tick_isset(rep->analyse_exp) && s->be->tcp_rep.inspect_delay)
321 					rep->analyse_exp = tick_add(now_ms, s->be->tcp_rep.inspect_delay);
322 				DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
323 				return 0;
324 			}
325 
326 			ret = acl_pass(ret);
327 			if (rule->cond->pol == ACL_COND_UNLESS)
328 				ret = !ret;
329 		}
330 
331 		if (ret) {
332 			act_flags |= ACT_FLAG_FIRST;
333 resume_execution:
334 			/* we have a matching rule. */
335 			if (rule->action == ACT_ACTION_ALLOW) {
336 				break;
337 			}
338 			else if (rule->action == ACT_ACTION_DENY) {
339 				si_must_kill_conn(chn_prod(rep));
340 				channel_abort(rep);
341 				channel_abort(&s->req);
342 				rep->analysers = 0;
343 
344 				_HA_ATOMIC_ADD(&s->be->be_counters.denied_resp, 1);
345 				_HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_resp, 1);
346 				if (sess->listener && sess->listener->counters)
347 					_HA_ATOMIC_ADD(&sess->listener->counters->denied_resp, 1);
348 
349 				if (!(s->flags & SF_ERR_MASK))
350 					s->flags |= SF_ERR_PRXCOND;
351 				if (!(s->flags & SF_FINST_MASK))
352 					s->flags |= SF_FINST_D;
353 				DBG_TRACE_DEVEL("leaving on error", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA|STRM_EV_TCP_ERR, s);
354 				return 0;
355 			}
356 			else if (rule->action == ACT_TCP_CLOSE) {
357 				chn_prod(rep)->flags |= SI_FL_NOLINGER | SI_FL_NOHALF;
358 				si_must_kill_conn(chn_prod(rep));
359 				si_shutr(chn_prod(rep));
360 				si_shutw(chn_prod(rep));
361 				break;
362 			}
363 			else {
364 				/* Custom keywords. */
365 				if (!rule->action_ptr)
366 					continue;
367 
368 				if (partial & SMP_OPT_FINAL)
369 					act_flags |= ACT_FLAG_FINAL;
370 
371 				switch (rule->action_ptr(rule, s->be, s->sess, s, act_flags)) {
372 				case ACT_RET_ERR:
373 				case ACT_RET_CONT:
374 					continue;
375 				case ACT_RET_STOP:
376 				case ACT_RET_DONE:
377 					break;
378 				case ACT_RET_YIELD:
379 					channel_dont_close(rep);
380 					s->current_rule = rule;
381 					DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
382 					return 0;
383 				}
384 				break; /* ACT_RET_STOP/DONE */
385 			}
386 		}
387 	}
388 
389 	/* if we get there, it means we have no rule which matches, or
390 	 * we have an explicit accept, so we apply the default accept.
391 	 */
392 	rep->analysers &= ~an_bit;
393 	rep->analyse_exp = TICK_ETERNITY;
394 	DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_TCP_ANA, s);
395 	return 1;
396 }
397 
398 
399 /* This function performs the TCP layer4 analysis on the current request. It
400  * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
401  * matches or if no more rule matches. It can only use rules which don't need
402  * any data. This only works on connection-based client-facing stream interfaces.
403  */
tcp_exec_l4_rules(struct session * sess)404 int tcp_exec_l4_rules(struct session *sess)
405 {
406 	struct act_rule *rule;
407 	struct stksess *ts;
408 	struct stktable *t = NULL;
409 	struct connection *conn = objt_conn(sess->origin);
410 	int result = 1;
411 	enum acl_test_res ret;
412 
413 	if (!conn)
414 		return result;
415 
416 	list_for_each_entry(rule, &sess->fe->tcp_req.l4_rules, list) {
417 		ret = ACL_TEST_PASS;
418 
419 		if (rule->cond) {
420 			ret = acl_exec_cond(rule->cond, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
421 			ret = acl_pass(ret);
422 			if (rule->cond->pol == ACL_COND_UNLESS)
423 				ret = !ret;
424 		}
425 
426 		if (ret) {
427 			/* we have a matching rule. */
428 			if (rule->action == ACT_ACTION_ALLOW) {
429 				break;
430 			}
431 			else if (rule->action == ACT_ACTION_DENY) {
432 				_HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_conn, 1);
433 				if (sess->listener && sess->listener->counters)
434 					_HA_ATOMIC_ADD(&sess->listener->counters->denied_conn, 1);
435 
436 				result = 0;
437 				break;
438 			}
439 			else if (rule->action >= ACT_ACTION_TRK_SC0 && rule->action <= ACT_ACTION_TRK_SCMAX) {
440 				/* Note: only the first valid tracking parameter of each
441 				 * applies.
442 				 */
443 				struct stktable_key *key;
444 
445 				if (stkctr_entry(&sess->stkctr[trk_idx(rule->action)]))
446 					continue;
447 
448 				t = rule->arg.trk_ctr.table.t;
449 				key = stktable_fetch_key(t, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.trk_ctr.expr, NULL);
450 
451 				if (key && (ts = stktable_get_entry(t, key)))
452 					stream_track_stkctr(&sess->stkctr[trk_idx(rule->action)], t, ts);
453 			}
454 			else if (rule->action == ACT_TCP_EXPECT_PX) {
455 				if (!(conn->flags & (CO_FL_HANDSHAKE_NOSSL))) {
456 					if (xprt_add_hs(conn) < 0) {
457 						result = 0;
458 						break;
459 					}
460 				}
461 				conn->flags |= CO_FL_ACCEPT_PROXY;
462 			}
463 			else if (rule->action == ACT_TCP_EXPECT_CIP) {
464 				if (!(conn->flags & (CO_FL_HANDSHAKE_NOSSL))) {
465 					if (xprt_add_hs(conn) < 0) {
466 						result = 0;
467 						break;
468 					}
469 				}
470 				conn->flags |= CO_FL_ACCEPT_CIP;
471 			}
472 			else {
473 				/* Custom keywords. */
474 				if (!rule->action_ptr)
475 					break;
476 				switch (rule->action_ptr(rule, sess->fe, sess, NULL, ACT_FLAG_FINAL | ACT_FLAG_FIRST)) {
477 				case ACT_RET_YIELD:
478 					/* yield is not allowed at this point. If this return code is
479 					 * used it is a bug, so I prefer to abort the process.
480 					 */
481 					send_log(sess->fe, LOG_WARNING,
482 					         "Internal error: yield not allowed with tcp-request connection actions.");
483 				case ACT_RET_STOP:
484 				case ACT_RET_DONE:
485 					break;
486 				case ACT_RET_CONT:
487 					continue;
488 				case ACT_RET_ERR:
489 					result = 0;
490 					break;
491 				}
492 				break; /* ACT_RET_STOP/DONE */
493 			}
494 		}
495 	}
496 	return result;
497 }
498 
499 /* This function performs the TCP layer5 analysis on the current request. It
500  * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
501  * matches or if no more rule matches. It can only use rules which don't need
502  * any data. This only works on session-based client-facing stream interfaces.
503  * An example of valid use case is to track a stick-counter on the source
504  * address extracted from the proxy protocol.
505  */
tcp_exec_l5_rules(struct session * sess)506 int tcp_exec_l5_rules(struct session *sess)
507 {
508 	struct act_rule *rule;
509 	struct stksess *ts;
510 	struct stktable *t = NULL;
511 	int result = 1;
512 	enum acl_test_res ret;
513 
514 	list_for_each_entry(rule, &sess->fe->tcp_req.l5_rules, list) {
515 		ret = ACL_TEST_PASS;
516 
517 		if (rule->cond) {
518 			ret = acl_exec_cond(rule->cond, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
519 			ret = acl_pass(ret);
520 			if (rule->cond->pol == ACL_COND_UNLESS)
521 				ret = !ret;
522 		}
523 
524 		if (ret) {
525 			/* we have a matching rule. */
526 			if (rule->action == ACT_ACTION_ALLOW) {
527 				break;
528 			}
529 			else if (rule->action == ACT_ACTION_DENY) {
530 				_HA_ATOMIC_ADD(&sess->fe->fe_counters.denied_sess, 1);
531 				if (sess->listener && sess->listener->counters)
532 					_HA_ATOMIC_ADD(&sess->listener->counters->denied_sess, 1);
533 
534 				result = 0;
535 				break;
536 			}
537 			else if (rule->action >= ACT_ACTION_TRK_SC0 && rule->action <= ACT_ACTION_TRK_SCMAX) {
538 				/* Note: only the first valid tracking parameter of each
539 				 * applies.
540 				 */
541 				struct stktable_key *key;
542 
543 				if (stkctr_entry(&sess->stkctr[trk_idx(rule->action)]))
544 					continue;
545 
546 				t = rule->arg.trk_ctr.table.t;
547 				key = stktable_fetch_key(t, sess->fe, sess, NULL, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.trk_ctr.expr, NULL);
548 
549 				if (key && (ts = stktable_get_entry(t, key)))
550 					stream_track_stkctr(&sess->stkctr[trk_idx(rule->action)], t, ts);
551 			}
552 			else {
553 				/* Custom keywords. */
554 				if (!rule->action_ptr)
555 					break;
556 				switch (rule->action_ptr(rule, sess->fe, sess, NULL, ACT_FLAG_FINAL | ACT_FLAG_FIRST)) {
557 				case ACT_RET_YIELD:
558 					/* yield is not allowed at this point. If this return code is
559 					 * used it is a bug, so I prefer to abort the process.
560 					 */
561 					send_log(sess->fe, LOG_WARNING,
562 					         "Internal error: yield not allowed with tcp-request session actions.");
563 				case ACT_RET_STOP:
564 				case ACT_RET_DONE:
565 					break;
566 				case ACT_RET_CONT:
567 					continue;
568 				case ACT_RET_ERR:
569 					result = 0;
570 					break;
571 				}
572 				break; /* ACT_RET_STOP/DONE */
573 			}
574 		}
575 	}
576 	return result;
577 }
578 
579 /* Parse a tcp-response rule. Return a negative value in case of failure */
tcp_parse_response_rule(char ** args,int arg,int section_type,struct proxy * curpx,struct proxy * defpx,struct act_rule * rule,char ** err,unsigned int where,const char * file,int line)580 static int tcp_parse_response_rule(char **args, int arg, int section_type,
581                                    struct proxy *curpx, struct proxy *defpx,
582                                    struct act_rule *rule, char **err,
583                                    unsigned int where,
584                                    const char *file, int line)
585 {
586 	if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
587 		memprintf(err, "%s %s is only allowed in 'backend' sections",
588 		          args[0], args[1]);
589 		return -1;
590 	}
591 
592 	if (strcmp(args[arg], "accept") == 0) {
593 		arg++;
594 		rule->action = ACT_ACTION_ALLOW;
595 	}
596 	else if (strcmp(args[arg], "reject") == 0) {
597 		arg++;
598 		rule->action = ACT_ACTION_DENY;
599 	}
600 	else if (strcmp(args[arg], "close") == 0) {
601 		arg++;
602 		rule->action = ACT_TCP_CLOSE;
603 	}
604 	else {
605 		struct action_kw *kw;
606 		kw = tcp_res_cont_action(args[arg]);
607 		if (kw) {
608 			arg++;
609 			rule->from = ACT_F_TCP_RES_CNT;
610 			rule->kw = kw;
611 			if (kw->parse((const char **)args, &arg, curpx, rule, err) == ACT_RET_PRS_ERR)
612 				return -1;
613 		} else {
614 			action_build_list(&tcp_res_cont_keywords, &trash);
615 			memprintf(err,
616 			          "'%s %s' expects 'accept', 'close', 'reject', %s in %s '%s' (got '%s')",
617 			          args[0], args[1], trash.area,
618 			          proxy_type_str(curpx), curpx->id, args[arg]);
619 			return -1;
620 		}
621 	}
622 
623 	if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
624 		if ((rule->cond = build_acl_cond(file, line, &curpx->acl, curpx, (const char **)args+arg, err)) == NULL) {
625 			memprintf(err,
626 			          "'%s %s %s' : error detected in %s '%s' while parsing '%s' condition : %s",
627 			          args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg], *err);
628 			return -1;
629 		}
630 	}
631 	else if (*args[arg]) {
632 		memprintf(err,
633 			 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (got '%s')",
634 			 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
635 		return -1;
636 	}
637 	return 0;
638 }
639 
640 
641 
642 /* Parse a tcp-request rule. Return a negative value in case of failure */
tcp_parse_request_rule(char ** args,int arg,int section_type,struct proxy * curpx,struct proxy * defpx,struct act_rule * rule,char ** err,unsigned int where,const char * file,int line)643 static int tcp_parse_request_rule(char **args, int arg, int section_type,
644                                   struct proxy *curpx, struct proxy *defpx,
645                                   struct act_rule *rule, char **err,
646                                   unsigned int where, const char *file, int line)
647 {
648 	if (curpx == defpx) {
649 		memprintf(err, "%s %s is not allowed in 'defaults' sections",
650 		          args[0], args[1]);
651 		return -1;
652 	}
653 
654 	if (!strcmp(args[arg], "accept")) {
655 		arg++;
656 		rule->action = ACT_ACTION_ALLOW;
657 	}
658 	else if (!strcmp(args[arg], "reject")) {
659 		arg++;
660 		rule->action = ACT_ACTION_DENY;
661 	}
662 	else if (strcmp(args[arg], "capture") == 0) {
663 		struct sample_expr *expr;
664 		struct cap_hdr *hdr;
665 		int kw = arg;
666 		int len = 0;
667 
668 		if (!(curpx->cap & PR_CAP_FE)) {
669 			memprintf(err,
670 			          "'%s %s %s' : proxy '%s' has no frontend capability",
671 			          args[0], args[1], args[kw], curpx->id);
672 			return -1;
673 		}
674 
675 		if (!(where & SMP_VAL_FE_REQ_CNT)) {
676 			memprintf(err,
677 				  "'%s %s' is not allowed in '%s %s' rules in %s '%s'",
678 				  args[arg], args[arg+1], args[0], args[1], proxy_type_str(curpx), curpx->id);
679 			return -1;
680 		}
681 
682 		arg++;
683 
684 		curpx->conf.args.ctx = ARGC_CAP;
685 		expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args);
686 		if (!expr) {
687 			memprintf(err,
688 			          "'%s %s %s' : %s",
689 			          args[0], args[1], args[kw], *err);
690 			return -1;
691 		}
692 
693 		if (!(expr->fetch->val & where)) {
694 			memprintf(err,
695 			          "'%s %s %s' : fetch method '%s' extracts information from '%s', none of which is available here",
696 			          args[0], args[1], args[kw], args[arg-1], sample_src_names(expr->fetch->use));
697 			release_sample_expr(expr);
698 			return -1;
699 		}
700 
701 		if (strcmp(args[arg], "len") == 0) {
702 			arg++;
703 			if (!args[arg]) {
704 				memprintf(err,
705 					  "'%s %s %s' : missing length value",
706 					  args[0], args[1], args[kw]);
707 				release_sample_expr(expr);
708 				return -1;
709 			}
710 			/* we copy the table name for now, it will be resolved later */
711 			len = atoi(args[arg]);
712 			if (len <= 0) {
713 				memprintf(err,
714 					  "'%s %s %s' : length must be > 0",
715 					  args[0], args[1], args[kw]);
716 				release_sample_expr(expr);
717 				return -1;
718 			}
719 			arg++;
720 		}
721 
722 		if (!len) {
723 			memprintf(err,
724 				  "'%s %s %s' : a positive 'len' argument is mandatory",
725 				  args[0], args[1], args[kw]);
726 			free(expr);
727 			return -1;
728 		}
729 
730 		hdr = calloc(1, sizeof(*hdr));
731 		hdr->next = curpx->req_cap;
732 		hdr->name = NULL; /* not a header capture */
733 		hdr->namelen = 0;
734 		hdr->len = len;
735 		hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
736 		hdr->index = curpx->nb_req_cap++;
737 
738 		curpx->req_cap = hdr;
739 		curpx->to_log |= LW_REQHDR;
740 
741 		/* check if we need to allocate an http_txn struct for HTTP parsing */
742 		curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
743 
744 		rule->arg.cap.expr = expr;
745 		rule->arg.cap.hdr = hdr;
746 		rule->action = ACT_TCP_CAPTURE;
747 	}
748 	else if (strncmp(args[arg], "track-sc", 8) == 0) {
749 		struct sample_expr *expr;
750 		int kw = arg;
751 		unsigned int tsc_num;
752 		const char *tsc_num_str;
753 
754 		arg++;
755 
756 		tsc_num_str = &args[kw][8];
757 		if (cfg_parse_track_sc_num(&tsc_num, tsc_num_str, tsc_num_str + strlen(tsc_num_str), err) == -1) {
758 			memprintf(err, "'%s %s %s' : %s", args[0], args[1], args[kw], *err);
759 			return -1;
760 		}
761 
762 		curpx->conf.args.ctx = ARGC_TRK;
763 		expr = sample_parse_expr(args, &arg, file, line, err, &curpx->conf.args);
764 		if (!expr) {
765 			memprintf(err,
766 			          "'%s %s %s' : %s",
767 			          args[0], args[1], args[kw], *err);
768 			return -1;
769 		}
770 
771 		if (!(expr->fetch->val & where)) {
772 			memprintf(err,
773 			          "'%s %s %s' : fetch method '%s' extracts information from '%s', none of which is available here",
774 			          args[0], args[1], args[kw], args[arg-1], sample_src_names(expr->fetch->use));
775 			release_sample_expr(expr);
776 			return -1;
777 		}
778 
779 		/* check if we need to allocate an http_txn struct for HTTP parsing */
780 		curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
781 
782 		if (strcmp(args[arg], "table") == 0) {
783 			arg++;
784 			if (!args[arg]) {
785 				memprintf(err,
786 					  "'%s %s %s' : missing table name",
787 					  args[0], args[1], args[kw]);
788 				release_sample_expr(expr);
789 				return -1;
790 			}
791 			/* we copy the table name for now, it will be resolved later */
792 			rule->arg.trk_ctr.table.n = strdup(args[arg]);
793 			arg++;
794 		}
795 		rule->arg.trk_ctr.expr = expr;
796 		rule->action = ACT_ACTION_TRK_SC0 + tsc_num;
797 		rule->check_ptr = check_trk_action;
798 	}
799 	else if (strcmp(args[arg], "expect-proxy") == 0) {
800 		if (strcmp(args[arg+1], "layer4") != 0) {
801 			memprintf(err,
802 				  "'%s %s %s' only supports 'layer4' in %s '%s' (got '%s')",
803 				  args[0], args[1], args[arg], proxy_type_str(curpx), curpx->id, args[arg+1]);
804 			return -1;
805 		}
806 
807 		if (!(where & SMP_VAL_FE_CON_ACC)) {
808 			memprintf(err,
809 				  "'%s %s' is not allowed in '%s %s' rules in %s '%s'",
810 				  args[arg], args[arg+1], args[0], args[1], proxy_type_str(curpx), curpx->id);
811 			return -1;
812 		}
813 
814 		arg += 2;
815 		rule->action = ACT_TCP_EXPECT_PX;
816 	}
817 	else if (strcmp(args[arg], "expect-netscaler-cip") == 0) {
818 		if (strcmp(args[arg+1], "layer4") != 0) {
819 			memprintf(err,
820 				  "'%s %s %s' only supports 'layer4' in %s '%s' (got '%s')",
821 				  args[0], args[1], args[arg], proxy_type_str(curpx), curpx->id, args[arg+1]);
822 			return -1;
823 		}
824 
825 		if (!(where & SMP_VAL_FE_CON_ACC)) {
826 			memprintf(err,
827 				  "'%s %s' is not allowed in '%s %s' rules in %s '%s'",
828 				  args[arg], args[arg+1], args[0], args[1], proxy_type_str(curpx), curpx->id);
829 			return -1;
830 		}
831 
832 		arg += 2;
833 		rule->action = ACT_TCP_EXPECT_CIP;
834 	}
835 	else {
836 		struct action_kw *kw;
837 		if (where & SMP_VAL_FE_CON_ACC) {
838 			/* L4 */
839 			kw = tcp_req_conn_action(args[arg]);
840 			rule->kw = kw;
841 			rule->from = ACT_F_TCP_REQ_CON;
842 		} else if (where & SMP_VAL_FE_SES_ACC) {
843 			/* L5 */
844 			kw = tcp_req_sess_action(args[arg]);
845 			rule->kw = kw;
846 			rule->from = ACT_F_TCP_REQ_SES;
847 		} else {
848 			/* L6 */
849 			kw = tcp_req_cont_action(args[arg]);
850 			rule->kw = kw;
851 			rule->from = ACT_F_TCP_REQ_CNT;
852 		}
853 		if (kw) {
854 			arg++;
855 			if (kw->parse((const char **)args, &arg, curpx, rule, err) == ACT_RET_PRS_ERR)
856 				return -1;
857 		} else {
858 			if (where & SMP_VAL_FE_CON_ACC)
859 				action_build_list(&tcp_req_conn_keywords, &trash);
860 			else if (where & SMP_VAL_FE_SES_ACC)
861 				action_build_list(&tcp_req_sess_keywords, &trash);
862 			else
863 				action_build_list(&tcp_req_cont_keywords, &trash);
864 			memprintf(err,
865 			          "'%s %s' expects 'accept', 'reject', 'track-sc0' ... 'track-sc%d', %s "
866 			          "in %s '%s' (got '%s').\n",
867 			          args[0], args[1], MAX_SESS_STKCTR-1,
868 			          trash.area, proxy_type_str(curpx),
869 			          curpx->id, args[arg]);
870 			return -1;
871 		}
872 	}
873 
874 	if (strcmp(args[arg], "if") == 0 || strcmp(args[arg], "unless") == 0) {
875 		if ((rule->cond = build_acl_cond(file, line, &curpx->acl, curpx, (const char **)args+arg, err)) == NULL) {
876 			memprintf(err,
877 			          "'%s %s %s' : error detected in %s '%s' while parsing '%s' condition : %s",
878 			          args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg], *err);
879 			return -1;
880 		}
881 	}
882 	else if (*args[arg]) {
883 		memprintf(err,
884 			 "'%s %s %s' only accepts 'if' or 'unless', in %s '%s' (got '%s')",
885 			 args[0], args[1], args[2], proxy_type_str(curpx), curpx->id, args[arg]);
886 		return -1;
887 	}
888 	return 0;
889 }
890 
891 /* This function should be called to parse a line starting with the "tcp-response"
892  * keyword.
893  */
tcp_parse_tcp_rep(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)894 static int tcp_parse_tcp_rep(char **args, int section_type, struct proxy *curpx,
895                              struct proxy *defpx, const char *file, int line,
896                              char **err)
897 {
898 	const char *ptr = NULL;
899 	unsigned int val;
900 	int warn = 0;
901 	int arg;
902 	struct act_rule *rule;
903 	unsigned int where;
904 	const struct acl *acl;
905 	const char *kw;
906 
907 	if (!*args[1]) {
908 		memprintf(err, "missing argument for '%s' in %s '%s'",
909 		          args[0], proxy_type_str(curpx), curpx->id);
910 		return -1;
911 	}
912 
913 	if (strcmp(args[1], "inspect-delay") == 0) {
914 		if (curpx == defpx || !(curpx->cap & PR_CAP_BE)) {
915 			memprintf(err, "%s %s is only allowed in 'backend' sections",
916 			          args[0], args[1]);
917 			return -1;
918 		}
919 
920 		if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
921 			memprintf(err,
922 			          "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
923 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
924 
925 			if (ptr == PARSE_TIME_OVER)
926 				memprintf(err, "%s (timer overflow in '%s', maximum value is 2147483647 ms or ~24.8 days)", *err, args[2]);
927 			else if (ptr == PARSE_TIME_UNDER)
928 				memprintf(err, "%s (timer underflow in '%s', minimum non-null value is 1 ms)", *err, args[2]);
929 			else if (ptr)
930 				memprintf(err, "%s (unexpected character '%c')", *err, *ptr);
931 			return -1;
932 		}
933 
934 		if (curpx->tcp_rep.inspect_delay) {
935 			memprintf(err, "ignoring %s %s (was already defined) in %s '%s'",
936 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
937 			return 1;
938 		}
939 		curpx->tcp_rep.inspect_delay = val;
940 		return 0;
941 	}
942 
943 	rule = calloc(1, sizeof(*rule));
944 	LIST_INIT(&rule->list);
945 	arg = 1;
946 	where = 0;
947 
948 	if (strcmp(args[1], "content") == 0) {
949 		arg++;
950 
951 		if (curpx->cap & PR_CAP_FE)
952 			where |= SMP_VAL_FE_RES_CNT;
953 		if (curpx->cap & PR_CAP_BE)
954 			where |= SMP_VAL_BE_RES_CNT;
955 
956 		if (tcp_parse_response_rule(args, arg, section_type, curpx, defpx, rule, err, where, file, line) < 0)
957 			goto error;
958 
959 		acl = rule->cond ? acl_cond_conflicts(rule->cond, where) : NULL;
960 		if (acl) {
961 			if (acl->name && *acl->name)
962 				memprintf(err,
963 					  "acl '%s' will never match in '%s %s' because it only involves keywords that are incompatible with '%s'",
964 					  acl->name, args[0], args[1], sample_ckp_names(where));
965 			else
966 				memprintf(err,
967 					  "anonymous acl will never match in '%s %s' because it uses keyword '%s' which is incompatible with '%s'",
968 					  args[0], args[1],
969 					  LIST_ELEM(acl->expr.n, struct acl_expr *, list)->kw,
970 					  sample_ckp_names(where));
971 
972 			warn++;
973 		}
974 		else if (rule->cond && acl_cond_kw_conflicts(rule->cond, where, &acl, &kw)) {
975 			if (acl->name && *acl->name)
976 				memprintf(err,
977 					  "acl '%s' involves keyword '%s' which is incompatible with '%s'",
978 					  acl->name, kw, sample_ckp_names(where));
979 			else
980 				memprintf(err,
981 					  "anonymous acl involves keyword '%s' which is incompatible with '%s'",
982 					  kw, sample_ckp_names(where));
983 			warn++;
984 		}
985 
986 		LIST_ADDQ(&curpx->tcp_rep.inspect_rules, &rule->list);
987 	}
988 	else {
989 		memprintf(err,
990 		          "'%s' expects 'inspect-delay' or 'content' in %s '%s' (got '%s')",
991 		          args[0], proxy_type_str(curpx), curpx->id, args[1]);
992 		goto error;
993 	}
994 
995 	return warn;
996  error:
997 	free(rule);
998 	return -1;
999 }
1000 
1001 
1002 /* This function should be called to parse a line starting with the "tcp-request"
1003  * keyword.
1004  */
tcp_parse_tcp_req(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)1005 static int tcp_parse_tcp_req(char **args, int section_type, struct proxy *curpx,
1006                              struct proxy *defpx, const char *file, int line,
1007                              char **err)
1008 {
1009 	const char *ptr = NULL;
1010 	unsigned int val;
1011 	int warn = 0;
1012 	int arg;
1013 	struct act_rule *rule;
1014 	unsigned int where;
1015 	const struct acl *acl;
1016 	const char *kw;
1017 
1018 	if (!*args[1]) {
1019 		if (curpx == defpx)
1020 			memprintf(err, "missing argument for '%s' in defaults section", args[0]);
1021 		else
1022 			memprintf(err, "missing argument for '%s' in %s '%s'",
1023 			          args[0], proxy_type_str(curpx), curpx->id);
1024 		return -1;
1025 	}
1026 
1027 	if (!strcmp(args[1], "inspect-delay")) {
1028 		if (curpx == defpx) {
1029 			memprintf(err, "%s %s is not allowed in 'defaults' sections",
1030 			          args[0], args[1]);
1031 			return -1;
1032 		}
1033 
1034 		if (!*args[2] || (ptr = parse_time_err(args[2], &val, TIME_UNIT_MS))) {
1035 			memprintf(err,
1036 			          "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
1037 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
1038 
1039 			if (ptr == PARSE_TIME_OVER)
1040 				memprintf(err, "%s (timer overflow in '%s', maximum value is 2147483647 ms or ~24.8 days)", *err, args[2]);
1041 			else if (ptr == PARSE_TIME_UNDER)
1042 				memprintf(err, "%s (timer underflow in '%s', minimum non-null value is 1 ms)", *err, args[2]);
1043 			else if (ptr)
1044 				memprintf(err, "%s (unexpected character '%c')", *err, *ptr);
1045 			return -1;
1046 		}
1047 
1048 		if (curpx->tcp_req.inspect_delay) {
1049 			memprintf(err, "ignoring %s %s (was already defined) in %s '%s'",
1050 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
1051 			return 1;
1052 		}
1053 		curpx->tcp_req.inspect_delay = val;
1054 		return 0;
1055 	}
1056 
1057 	rule = calloc(1, sizeof(*rule));
1058 	LIST_INIT(&rule->list);
1059 	arg = 1;
1060 	where = 0;
1061 
1062 	if (strcmp(args[1], "content") == 0) {
1063 		arg++;
1064 
1065 		if (curpx->cap & PR_CAP_FE)
1066 			where |= SMP_VAL_FE_REQ_CNT;
1067 		if (curpx->cap & PR_CAP_BE)
1068 			where |= SMP_VAL_BE_REQ_CNT;
1069 
1070 		if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, where, file, line) < 0)
1071 			goto error;
1072 
1073 		acl = rule->cond ? acl_cond_conflicts(rule->cond, where) : NULL;
1074 		if (acl) {
1075 			if (acl->name && *acl->name)
1076 				memprintf(err,
1077 					  "acl '%s' will never match in '%s %s' because it only involves keywords that are incompatible with '%s'",
1078 					  acl->name, args[0], args[1], sample_ckp_names(where));
1079 			else
1080 				memprintf(err,
1081 					  "anonymous acl will never match in '%s %s' because it uses keyword '%s' which is incompatible with '%s'",
1082 					  args[0], args[1],
1083 					  LIST_ELEM(acl->expr.n, struct acl_expr *, list)->kw,
1084 					  sample_ckp_names(where));
1085 
1086 			warn++;
1087 		}
1088 		else if (rule->cond && acl_cond_kw_conflicts(rule->cond, where, &acl, &kw)) {
1089 			if (acl->name && *acl->name)
1090 				memprintf(err,
1091 					  "acl '%s' involves keyword '%s' which is incompatible with '%s'",
1092 					  acl->name, kw, sample_ckp_names(where));
1093 			else
1094 				memprintf(err,
1095 					  "anonymous acl involves keyword '%s' which is incompatible with '%s'",
1096 					  kw, sample_ckp_names(where));
1097 			warn++;
1098 		}
1099 
1100 		/* the following function directly emits the warning */
1101 		warnif_misplaced_tcp_cont(curpx, file, line, args[0]);
1102 		LIST_ADDQ(&curpx->tcp_req.inspect_rules, &rule->list);
1103 	}
1104 	else if (strcmp(args[1], "connection") == 0) {
1105 		arg++;
1106 
1107 		if (!(curpx->cap & PR_CAP_FE)) {
1108 			memprintf(err, "%s %s is not allowed because %s %s is not a frontend",
1109 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
1110 			goto error;
1111 		}
1112 
1113 		where |= SMP_VAL_FE_CON_ACC;
1114 
1115 		if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, where, file, line) < 0)
1116 			goto error;
1117 
1118 		acl = rule->cond ? acl_cond_conflicts(rule->cond, where) : NULL;
1119 		if (acl) {
1120 			if (acl->name && *acl->name)
1121 				memprintf(err,
1122 					  "acl '%s' will never match in '%s %s' because it only involves keywords that are incompatible with '%s'",
1123 					  acl->name, args[0], args[1], sample_ckp_names(where));
1124 			else
1125 				memprintf(err,
1126 					  "anonymous acl will never match in '%s %s' because it uses keyword '%s' which is incompatible with '%s'",
1127 					  args[0], args[1],
1128 					  LIST_ELEM(acl->expr.n, struct acl_expr *, list)->kw,
1129 					  sample_ckp_names(where));
1130 
1131 			warn++;
1132 		}
1133 		else if (rule->cond && acl_cond_kw_conflicts(rule->cond, where, &acl, &kw)) {
1134 			if (acl->name && *acl->name)
1135 				memprintf(err,
1136 					  "acl '%s' involves keyword '%s' which is incompatible with '%s'",
1137 					  acl->name, kw, sample_ckp_names(where));
1138 			else
1139 				memprintf(err,
1140 					  "anonymous acl involves keyword '%s' which is incompatible with '%s'",
1141 					  kw, sample_ckp_names(where));
1142 			warn++;
1143 		}
1144 
1145 		/* the following function directly emits the warning */
1146 		warnif_misplaced_tcp_conn(curpx, file, line, args[0]);
1147 		LIST_ADDQ(&curpx->tcp_req.l4_rules, &rule->list);
1148 	}
1149 	else if (strcmp(args[1], "session") == 0) {
1150 		arg++;
1151 
1152 		if (!(curpx->cap & PR_CAP_FE)) {
1153 			memprintf(err, "%s %s is not allowed because %s %s is not a frontend",
1154 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
1155 			goto error;
1156 		}
1157 
1158 		where |= SMP_VAL_FE_SES_ACC;
1159 
1160 		if (tcp_parse_request_rule(args, arg, section_type, curpx, defpx, rule, err, where, file, line) < 0)
1161 			goto error;
1162 
1163 		acl = rule->cond ? acl_cond_conflicts(rule->cond, where) : NULL;
1164 		if (acl) {
1165 			if (acl->name && *acl->name)
1166 				memprintf(err,
1167 					  "acl '%s' will never match in '%s %s' because it only involves keywords that are incompatible with '%s'",
1168 					  acl->name, args[0], args[1], sample_ckp_names(where));
1169 			else
1170 				memprintf(err,
1171 					  "anonymous acl will never match in '%s %s' because it uses keyword '%s' which is incompatible with '%s'",
1172 					  args[0], args[1],
1173 					  LIST_ELEM(acl->expr.n, struct acl_expr *, list)->kw,
1174 					  sample_ckp_names(where));
1175 			warn++;
1176 		}
1177 		else if (rule->cond && acl_cond_kw_conflicts(rule->cond, where, &acl, &kw)) {
1178 			if (acl->name && *acl->name)
1179 				memprintf(err,
1180 					  "acl '%s' involves keyword '%s' which is incompatible with '%s'",
1181 					  acl->name, kw, sample_ckp_names(where));
1182 			else
1183 				memprintf(err,
1184 					  "anonymous acl involves keyword '%s' which is incompatible with '%s'",
1185 					  kw, sample_ckp_names(where));
1186 			warn++;
1187 		}
1188 
1189 		/* the following function directly emits the warning */
1190 		warnif_misplaced_tcp_sess(curpx, file, line, args[0]);
1191 		LIST_ADDQ(&curpx->tcp_req.l5_rules, &rule->list);
1192 	}
1193 	else {
1194 		if (curpx == defpx)
1195 			memprintf(err,
1196 			          "'%s' expects 'inspect-delay', 'connection', or 'content' in defaults section (got '%s')",
1197 			          args[0], args[1]);
1198 		else
1199 			memprintf(err,
1200 			          "'%s' expects 'inspect-delay', 'connection', or 'content' in %s '%s' (got '%s')",
1201 			          args[0], proxy_type_str(curpx), curpx->id, args[1]);
1202 		goto error;
1203 	}
1204 
1205 	return warn;
1206  error:
1207 	free(rule);
1208 	return -1;
1209 }
1210 
1211 static struct cfg_kw_list cfg_kws = {ILH, {
1212 	{ CFG_LISTEN, "tcp-request",  tcp_parse_tcp_req },
1213 	{ CFG_LISTEN, "tcp-response", tcp_parse_tcp_rep },
1214 	{ 0, NULL, NULL },
1215 }};
1216 
1217 INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
1218 
1219 /*
1220  * Local variables:
1221  *  c-indent-level: 8
1222  *  c-basic-offset: 8
1223  * End:
1224  */
1225