blob: 19e7eeaf88dfc2201c88081437373a333eb7b625 [file] [log] [blame]
Willy Tarreauaeae66c2020-08-28 11:03:28 +02001/*
2 * AF_INET/AF_INET6 SOCK_STREAM protocol layer (tcp)
3 *
4 * Copyright 2000-2013 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
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20
21#include <sys/param.h>
22#include <sys/socket.h>
23#include <sys/types.h>
24
25#include <netinet/tcp.h>
26#include <netinet/in.h>
27
28#include <haproxy/action-t.h>
29#include <haproxy/api.h>
30#include <haproxy/arg.h>
31#include <haproxy/channel.h>
32#include <haproxy/connection.h>
Christopher Faulet8da67aa2022-03-29 17:53:09 +020033#include <haproxy/cs_utils.h>
Willy Tarreauaeae66c2020-08-28 11:03:28 +020034#include <haproxy/global.h>
35#include <haproxy/http_rules.h>
36#include <haproxy/proto_tcp.h>
37#include <haproxy/proxy-t.h>
38#include <haproxy/sample.h>
Christopher Fauletd69377e2021-10-25 08:26:34 +020039#include <haproxy/session.h>
40#include <haproxy/stream_interface.h>
Willy Tarreauaeae66c2020-08-28 11:03:28 +020041#include <haproxy/tcp_rules.h>
42#include <haproxy/tools.h>
43
44/*
45 * Execute the "set-src" action. May be called from {tcp,http}request.
46 * It only changes the address and tries to preserve the original port. If the
47 * previous family was neither AF_INET nor AF_INET6, the port is set to zero.
48 */
49static enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px,
50 struct session *sess, struct stream *s, int flags)
51{
52 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +020053 struct sockaddr_storage *src;
54 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020055
Christopher Fauletd69377e2021-10-25 08:26:34 +020056 switch (rule->from) {
57 case ACT_F_TCP_REQ_CON:
58 cli_conn = objt_conn(sess->origin);
59 if (!cli_conn || !conn_get_src(cli_conn))
60 goto end;
61 src = cli_conn->src;
62 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020063
Christopher Fauletd69377e2021-10-25 08:26:34 +020064 case ACT_F_TCP_REQ_SES:
65 if (!sess_get_src(sess))
66 goto end;
67 src = sess->src;
68 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020069
Christopher Fauletd69377e2021-10-25 08:26:34 +020070 case ACT_F_TCP_REQ_CNT:
71 case ACT_F_HTTP_REQ:
Christopher Faulet8da67aa2022-03-29 17:53:09 +020072 if (!cs_get_src(s->csf))
Christopher Fauletd69377e2021-10-25 08:26:34 +020073 goto end;
Christopher Faulet8da67aa2022-03-29 17:53:09 +020074 src = s->csf->src;
Christopher Fauletd69377e2021-10-25 08:26:34 +020075 break;
76
77 default:
78 goto end;
79 }
80
81 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR);
82 if (smp) {
83 int port = get_net_port(src);
84
85 if (smp->data.type == SMP_T_IPV4) {
86 ((struct sockaddr_in *)src)->sin_family = AF_INET;
87 ((struct sockaddr_in *)src)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
88 ((struct sockaddr_in *)src)->sin_port = port;
89 } else if (smp->data.type == SMP_T_IPV6) {
90 ((struct sockaddr_in6 *)src)->sin6_family = AF_INET6;
91 memcpy(&((struct sockaddr_in6 *)src)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
92 ((struct sockaddr_in6 *)src)->sin6_port = port;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020093 }
Willy Tarreauaeae66c2020-08-28 11:03:28 +020094 }
Christopher Fauletd69377e2021-10-25 08:26:34 +020095
96 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +020097 return ACT_RET_CONT;
98}
99
100/*
101 * Execute the "set-dst" action. May be called from {tcp,http}request.
102 * It only changes the address and tries to preserve the original port. If the
103 * previous family was neither AF_INET nor AF_INET6, the port is set to zero.
104 */
105static enum act_return tcp_action_req_set_dst(struct act_rule *rule, struct proxy *px,
106 struct session *sess, struct stream *s, int flags)
107{
108 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200109 struct sockaddr_storage *dst;
110 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200111
Christopher Fauletd69377e2021-10-25 08:26:34 +0200112 switch (rule->from) {
113 case ACT_F_TCP_REQ_CON:
114 cli_conn = objt_conn(sess->origin);
115 if (!cli_conn || !conn_get_dst(cli_conn))
116 goto end;
117 dst = cli_conn->dst;
118 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200119
Christopher Fauletd69377e2021-10-25 08:26:34 +0200120 case ACT_F_TCP_REQ_SES:
121 if (!sess_get_dst(sess))
122 goto end;
123 dst = sess->dst;
124 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200125
Christopher Fauletd69377e2021-10-25 08:26:34 +0200126 case ACT_F_TCP_REQ_CNT:
127 case ACT_F_HTTP_REQ:
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200128 if (!cs_get_dst(s->csf))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200129 goto end;
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200130 dst = s->csf->dst;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200131 break;
132
133 default:
134 goto end;
135 }
136
137 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR);
138 if (smp) {
139 int port = get_net_port(dst);
140
141 if (smp->data.type == SMP_T_IPV4) {
142 ((struct sockaddr_in *)dst)->sin_family = AF_INET;
143 ((struct sockaddr_in *)dst)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
144 ((struct sockaddr_in *)dst)->sin_port = port;
145 } else if (smp->data.type == SMP_T_IPV6) {
146 ((struct sockaddr_in6 *)dst)->sin6_family = AF_INET6;
147 memcpy(&((struct sockaddr_in6 *)dst)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
148 ((struct sockaddr_in6 *)dst)->sin6_port = port;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200149 }
150 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200151
152 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200153 return ACT_RET_CONT;
154}
155
156/*
157 * Execute the "set-src-port" action. May be called from {tcp,http}request.
158 * We must test the sin_family before setting the port. If the address family
159 * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0"
160 * and the port is assigned.
161 */
162static enum act_return tcp_action_req_set_src_port(struct act_rule *rule, struct proxy *px,
163 struct session *sess, struct stream *s, int flags)
164{
165 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200166 struct sockaddr_storage *src;
167 struct sample *smp;
168
169 switch (rule->from) {
170 case ACT_F_TCP_REQ_CON:
171 cli_conn = objt_conn(sess->origin);
172 if (!cli_conn || !conn_get_src(cli_conn))
173 goto end;
174 src = cli_conn->src;
175 break;
176
177 case ACT_F_TCP_REQ_SES:
178 if (!sess_get_src(sess))
179 goto end;
180 src = sess->src;
181 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200182
Christopher Fauletd69377e2021-10-25 08:26:34 +0200183 case ACT_F_TCP_REQ_CNT:
184 case ACT_F_HTTP_REQ:
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200185 if (!cs_get_src(s->csf))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200186 goto end;
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200187 src = s->csf->src;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200188 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200189
Christopher Fauletd69377e2021-10-25 08:26:34 +0200190 default:
191 goto end;
192 }
193
194 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT);
195 if (smp) {
196 if (src->ss_family == AF_INET6) {
197 ((struct sockaddr_in6 *)src)->sin6_port = htons(smp->data.u.sint);
198 } else {
199 if (src->ss_family != AF_INET) {
200 src->ss_family = AF_INET;
201 ((struct sockaddr_in *)src)->sin_addr.s_addr = 0;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200202 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200203 ((struct sockaddr_in *)src)->sin_port = htons(smp->data.u.sint);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200204 }
205 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200206
207 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200208 return ACT_RET_CONT;
209}
210
211/*
212 * Execute the "set-dst-port" action. May be called from {tcp,http}request.
213 * We must test the sin_family before setting the port. If the address family
214 * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0"
215 * and the port is assigned.
216 */
217static enum act_return tcp_action_req_set_dst_port(struct act_rule *rule, struct proxy *px,
218 struct session *sess, struct stream *s, int flags)
219{
220 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200221 struct sockaddr_storage *dst;
222 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200223
Christopher Fauletd69377e2021-10-25 08:26:34 +0200224 switch (rule->from) {
225 case ACT_F_TCP_REQ_CON:
226 cli_conn = objt_conn(sess->origin);
227 if (!cli_conn || !conn_get_dst(cli_conn))
228 goto end;
229 dst = cli_conn->dst;
230 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200231
Christopher Fauletd69377e2021-10-25 08:26:34 +0200232 case ACT_F_TCP_REQ_SES:
233 if (!sess_get_dst(sess))
234 goto end;
235 dst = sess->dst;
236 break;
237
238 case ACT_F_TCP_REQ_CNT:
239 case ACT_F_HTTP_REQ:
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200240 if (!cs_get_dst(s->csf))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200241 goto end;
Christopher Faulet8da67aa2022-03-29 17:53:09 +0200242 dst = s->csf->dst;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200243 break;
244
245 default:
246 goto end;
247 }
248
249 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT);
250 if (smp) {
251 if (dst->ss_family == AF_INET6) {
252 ((struct sockaddr_in6 *)dst)->sin6_port = htons(smp->data.u.sint);
253 } else {
254 if (dst->ss_family != AF_INET) {
255 dst->ss_family = AF_INET;
256 ((struct sockaddr_in *)dst)->sin_addr.s_addr = 0;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200257 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200258 ((struct sockaddr_in *)dst)->sin_port = htons(smp->data.u.sint);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200259 }
260 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200261
262 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200263 return ACT_RET_CONT;
264}
265
266/* Executes the "silent-drop" action. May be called from {tcp,http}{request,response} */
267static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct proxy *px,
268 struct session *sess, struct stream *strm, int flags)
269{
270 struct connection *conn = objt_conn(sess->origin);
271
272 if (!conn)
273 goto out;
274
275 if (!conn_ctrl_ready(conn))
276 goto out;
277
278#ifdef TCP_QUICKACK
279 /* drain is needed only to send the quick ACK */
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100280 conn_ctrl_drain(conn);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200281
282 /* re-enable quickack if it was disabled to ack all data and avoid
283 * retransmits from the client that might trigger a real reset.
284 */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200285 setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200286#endif
287 /* lingering must absolutely be disabled so that we don't send a
288 * shutdown(), this is critical to the TCP_REPAIR trick. When no stream
289 * is present, returning with ERR will cause lingering to be disabled.
290 */
291 if (strm)
Christopher Faulet8abe7122022-03-30 15:10:18 +0200292 strm->csf->flags |= CS_FL_NOLINGER;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200293
Willy Tarreaue2226792022-04-11 18:04:33 +0200294 if (conn->flags & CO_FL_FDLESS)
295 goto out;
296
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200297 /* We're on the client-facing side, we must force to disable lingering to
298 * ensure we will use an RST exclusively and kill any pending data.
299 */
Willy Tarreaub41a6e92021-04-06 17:49:19 +0200300 HA_ATOMIC_OR(&fdtab[conn->handle.fd].state, FD_LINGER_RISK);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200301
302#ifdef TCP_REPAIR
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200303 if (setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_REPAIR, &one, sizeof(one)) == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200304 /* socket will be quiet now */
305 goto out;
306 }
307#endif
308 /* either TCP_REPAIR is not defined or it failed (eg: permissions).
309 * Let's fall back on the TTL trick, though it only works for routed
310 * network and has no effect on local net.
311 */
312#ifdef IP_TTL
Willy Tarreauab79ee82021-03-30 17:23:50 +0200313 if (conn->src && conn->src->ss_family == AF_INET)
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200314 setsockopt(conn->handle.fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
Willy Tarreauab79ee82021-03-30 17:23:50 +0200315#endif
316#ifdef IPV6_UNICAST_HOPS
Willy Tarreauda231952021-03-31 08:29:27 +0200317 if (conn->src && conn->src->ss_family == AF_INET6)
318 setsockopt(conn->handle.fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
319#endif
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200320 out:
321 /* kill the stream if any */
322 if (strm) {
323 channel_abort(&strm->req);
324 channel_abort(&strm->res);
325 strm->req.analysers &= AN_REQ_FLT_END;
326 strm->res.analysers &= AN_RES_FLT_END;
327 if (strm->flags & SF_BE_ASSIGNED)
Willy Tarreau4781b152021-04-06 13:53:36 +0200328 _HA_ATOMIC_INC(&strm->be->be_counters.denied_req);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200329 if (!(strm->flags & SF_ERR_MASK))
330 strm->flags |= SF_ERR_PRXCOND;
331 if (!(strm->flags & SF_FINST_MASK))
332 strm->flags |= SF_FINST_R;
333 }
334
Willy Tarreau4781b152021-04-06 13:53:36 +0200335 _HA_ATOMIC_INC(&sess->fe->fe_counters.denied_req);
William Lallemand36119de2021-03-08 15:26:48 +0100336 if (sess->listener && sess->listener->counters)
Willy Tarreau4781b152021-04-06 13:53:36 +0200337 _HA_ATOMIC_INC(&sess->listener->counters->denied_req);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200338
339 return ACT_RET_ABRT;
340}
341
Christopher Faulet469c06c2021-06-25 15:11:35 +0200342
David Carlierbae4cb22021-07-03 10:15:15 +0100343#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
Christopher Faulet469c06c2021-06-25 15:11:35 +0200344static enum act_return tcp_action_set_mark(struct act_rule *rule, struct proxy *px,
345 struct session *sess, struct stream *s, int flags)
346{
347 conn_set_mark(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
348 return ACT_RET_CONT;
349}
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200350#endif
Christopher Faulet469c06c2021-06-25 15:11:35 +0200351
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200352#ifdef IP_TOS
Christopher Faulet469c06c2021-06-25 15:11:35 +0200353static enum act_return tcp_action_set_tos(struct act_rule *rule, struct proxy *px,
354 struct session *sess, struct stream *s, int flags)
355{
356 conn_set_tos(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
357 return ACT_RET_CONT;
358}
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200359#endif
Christopher Faulet469c06c2021-06-25 15:11:35 +0200360
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200361/* parse "set-{src,dst}[-port]" action */
362static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struct proxy *px,
363 struct act_rule *rule, char **err)
364{
365 int cur_arg;
366 struct sample_expr *expr;
367 unsigned int where;
368
369 cur_arg = *orig_arg;
370 expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
371 if (!expr)
372 return ACT_RET_PRS_ERR;
373
374 where = 0;
375 if (px->cap & PR_CAP_FE)
376 where |= SMP_VAL_FE_HRQ_HDR;
377 if (px->cap & PR_CAP_BE)
378 where |= SMP_VAL_BE_HRQ_HDR;
379
380 if (!(expr->fetch->val & where)) {
381 memprintf(err,
382 "fetch method '%s' extracts information from '%s', none of which is available here",
383 args[cur_arg-1], sample_src_names(expr->fetch->use));
384 free(expr);
385 return ACT_RET_PRS_ERR;
386 }
387 rule->arg.expr = expr;
388 rule->action = ACT_CUSTOM;
389
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100390 if (strcmp(args[*orig_arg - 1], "set-src") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200391 rule->action_ptr = tcp_action_req_set_src;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100392 } else if (strcmp(args[*orig_arg - 1], "set-src-port") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200393 rule->action_ptr = tcp_action_req_set_src_port;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100394 } else if (strcmp(args[*orig_arg - 1], "set-dst") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200395 rule->action_ptr = tcp_action_req_set_dst;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100396 } else if (strcmp(args[*orig_arg - 1], "set-dst-port") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200397 rule->action_ptr = tcp_action_req_set_dst_port;
398 } else {
399 return ACT_RET_PRS_ERR;
400 }
401
402 (*orig_arg)++;
403
Christopher Faulet469c06c2021-06-25 15:11:35 +0200404 return ACT_RET_PRS_OK;
405}
406
407
408/* Parse a "set-mark" action. It takes the MARK value as argument. It returns
409 * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
410 */
411static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, struct proxy *px,
412 struct act_rule *rule, char **err)
413{
David Carlierbae4cb22021-07-03 10:15:15 +0100414#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
Christopher Faulet469c06c2021-06-25 15:11:35 +0200415 char *endp;
416 unsigned int mark;
417
418 if (!*args[*cur_arg]) {
419 memprintf(err, "expects exactly 1 argument (integer/hex value)");
420 return ACT_RET_PRS_ERR;
421 }
422 mark = strtoul(args[*cur_arg], &endp, 0);
423 if (endp && *endp != '\0') {
424 memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
425 return ACT_RET_PRS_ERR;
426 }
427
428 (*cur_arg)++;
429
430 /* Register processing function. */
431 rule->action_ptr = tcp_action_set_mark;
432 rule->action = ACT_CUSTOM;
433 rule->arg.act.p[0] = (void *)(uintptr_t)mark;
434 global.last_checks |= LSTCHK_NETADM;
435 return ACT_RET_PRS_OK;
436#else
David Carlierbae4cb22021-07-03 10:15:15 +0100437 memprintf(err, "not supported on this platform (SO_MARK|SO_USER_COOKIE|SO_RTABLE undefined)");
Christopher Faulet469c06c2021-06-25 15:11:35 +0200438 return ACT_RET_PRS_ERR;
439#endif
440}
441
442
443/* Parse a "set-tos" action. It takes the TOS value as argument. It returns
444 * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
445 */
446static enum act_parse_ret tcp_parse_set_tos(const char **args, int *cur_arg, struct proxy *px,
447 struct act_rule *rule, char **err)
448{
449#ifdef IP_TOS
450 char *endp;
451 int tos;
452
453 if (!*args[*cur_arg]) {
454 memprintf(err, "expects exactly 1 argument (integer/hex value)");
455 return ACT_RET_PRS_ERR;
456 }
457 tos = strtol(args[*cur_arg], &endp, 0);
458 if (endp && *endp != '\0') {
459 memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
460 return ACT_RET_PRS_ERR;
461 }
462
463 (*cur_arg)++;
464
465 /* Register processing function. */
466 rule->action_ptr = tcp_action_set_tos;
467 rule->action = ACT_CUSTOM;
468 rule->arg.act.p[0] = (void *)(uintptr_t)tos;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200469 return ACT_RET_PRS_OK;
Christopher Faulet469c06c2021-06-25 15:11:35 +0200470#else
471 memprintf(err, "not supported on this platform (IP_TOS undefined)");
472 return ACT_RET_PRS_ERR;
473#endif
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200474}
475
476
477/* Parse a "silent-drop" action. It takes no argument. It returns ACT_RET_PRS_OK on
478 * success, ACT_RET_PRS_ERR on error.
479 */
480static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *orig_arg, struct proxy *px,
481 struct act_rule *rule, char **err)
482{
483 rule->action = ACT_CUSTOM;
484 rule->action_ptr = tcp_exec_action_silent_drop;
485 return ACT_RET_PRS_OK;
486}
487
488
489static struct action_kw_list tcp_req_conn_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200490 { "set-dst" , tcp_parse_set_src_dst },
491 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200492 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200493 { "set-src", tcp_parse_set_src_dst },
494 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200495 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200496 { "silent-drop", tcp_parse_silent_drop },
497 { /* END */ }
498}};
499
500INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions);
501
502static struct action_kw_list tcp_req_sess_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200503 { "set-dst" , tcp_parse_set_src_dst },
504 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200505 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200506 { "set-src", tcp_parse_set_src_dst },
507 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200508 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200509 { "silent-drop", tcp_parse_silent_drop },
510 { /* END */ }
511}};
512
513INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions);
514
515static struct action_kw_list tcp_req_cont_actions = {ILH, {
Christopher Faulet1e83b702021-06-23 12:07:21 +0200516 { "set-src", tcp_parse_set_src_dst },
517 { "set-src-port", tcp_parse_set_src_dst },
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200518 { "set-dst" , tcp_parse_set_src_dst },
519 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200520 { "set-mark", tcp_parse_set_mark },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200521 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200522 { "silent-drop", tcp_parse_silent_drop },
523 { /* END */ }
524}};
525
526INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions);
527
528static struct action_kw_list tcp_res_cont_actions = {ILH, {
Christopher Faulet469c06c2021-06-25 15:11:35 +0200529 { "set-mark", tcp_parse_set_mark },
530 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200531 { "silent-drop", tcp_parse_silent_drop },
532 { /* END */ }
533}};
534
535INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions);
536
537static struct action_kw_list http_req_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200538 { "set-dst", tcp_parse_set_src_dst },
539 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200540 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200541 { "set-src", tcp_parse_set_src_dst },
542 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200543 { "set-tos", tcp_parse_set_tos },
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200544 { "silent-drop", tcp_parse_silent_drop },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200545 { /* END */ }
546}};
547
548INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
549
550static struct action_kw_list http_res_actions = {ILH, {
Christopher Faulet469c06c2021-06-25 15:11:35 +0200551 { "set-mark", tcp_parse_set_mark },
552 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200553 { "silent-drop", tcp_parse_silent_drop },
554 { /* END */ }
555}};
556
557INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
558
559
560/*
561 * Local variables:
562 * c-indent-level: 8
563 * c-basic-offset: 8
564 * End:
565 */