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