blob: 04400d2107654d38c3472c57f4483d8fe9662eba [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>
33#include <haproxy/global.h>
34#include <haproxy/http_rules.h>
35#include <haproxy/proto_tcp.h>
36#include <haproxy/proxy-t.h>
37#include <haproxy/sample.h>
Christopher Fauletd69377e2021-10-25 08:26:34 +020038#include <haproxy/session.h>
39#include <haproxy/stream_interface.h>
Willy Tarreauaeae66c2020-08-28 11:03:28 +020040#include <haproxy/tcp_rules.h>
41#include <haproxy/tools.h>
42
43/*
44 * Execute the "set-src" action. May be called from {tcp,http}request.
45 * It only changes the address and tries to preserve the original port. If the
46 * previous family was neither AF_INET nor AF_INET6, the port is set to zero.
47 */
48static enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px,
49 struct session *sess, struct stream *s, int flags)
50{
51 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +020052 struct sockaddr_storage *src;
53 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020054
Christopher Fauletd69377e2021-10-25 08:26:34 +020055 switch (rule->from) {
56 case ACT_F_TCP_REQ_CON:
57 cli_conn = objt_conn(sess->origin);
58 if (!cli_conn || !conn_get_src(cli_conn))
59 goto end;
60 src = cli_conn->src;
61 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020062
Christopher Fauletd69377e2021-10-25 08:26:34 +020063 case ACT_F_TCP_REQ_SES:
64 if (!sess_get_src(sess))
65 goto end;
66 src = sess->src;
67 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020068
Christopher Fauletd69377e2021-10-25 08:26:34 +020069 case ACT_F_TCP_REQ_CNT:
70 case ACT_F_HTTP_REQ:
Christopher Faulet0de82722021-12-23 13:59:47 +010071 if (!si_get_src(cs_si(s->csf)))
Christopher Fauletd69377e2021-10-25 08:26:34 +020072 goto end;
Christopher Faulet0de82722021-12-23 13:59:47 +010073 src = cs_si(s->csf)->src;
Christopher Fauletd69377e2021-10-25 08:26:34 +020074 break;
75
76 default:
77 goto end;
78 }
79
80 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR);
81 if (smp) {
82 int port = get_net_port(src);
83
84 if (smp->data.type == SMP_T_IPV4) {
85 ((struct sockaddr_in *)src)->sin_family = AF_INET;
86 ((struct sockaddr_in *)src)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
87 ((struct sockaddr_in *)src)->sin_port = port;
88 } else if (smp->data.type == SMP_T_IPV6) {
89 ((struct sockaddr_in6 *)src)->sin6_family = AF_INET6;
90 memcpy(&((struct sockaddr_in6 *)src)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
91 ((struct sockaddr_in6 *)src)->sin6_port = port;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020092 }
Willy Tarreauaeae66c2020-08-28 11:03:28 +020093 }
Christopher Fauletd69377e2021-10-25 08:26:34 +020094
95 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +020096 return ACT_RET_CONT;
97}
98
99/*
100 * Execute the "set-dst" action. May be called from {tcp,http}request.
101 * It only changes the address and tries to preserve the original port. If the
102 * previous family was neither AF_INET nor AF_INET6, the port is set to zero.
103 */
104static enum act_return tcp_action_req_set_dst(struct act_rule *rule, struct proxy *px,
105 struct session *sess, struct stream *s, int flags)
106{
107 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200108 struct sockaddr_storage *dst;
109 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200110
Christopher Fauletd69377e2021-10-25 08:26:34 +0200111 switch (rule->from) {
112 case ACT_F_TCP_REQ_CON:
113 cli_conn = objt_conn(sess->origin);
114 if (!cli_conn || !conn_get_dst(cli_conn))
115 goto end;
116 dst = cli_conn->dst;
117 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200118
Christopher Fauletd69377e2021-10-25 08:26:34 +0200119 case ACT_F_TCP_REQ_SES:
120 if (!sess_get_dst(sess))
121 goto end;
122 dst = sess->dst;
123 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200124
Christopher Fauletd69377e2021-10-25 08:26:34 +0200125 case ACT_F_TCP_REQ_CNT:
126 case ACT_F_HTTP_REQ:
Christopher Faulet0de82722021-12-23 13:59:47 +0100127 if (!si_get_dst(cs_si(s->csf)))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200128 goto end;
Christopher Faulet0de82722021-12-23 13:59:47 +0100129 dst = cs_si(s->csf)->dst;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200130 break;
131
132 default:
133 goto end;
134 }
135
136 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR);
137 if (smp) {
138 int port = get_net_port(dst);
139
140 if (smp->data.type == SMP_T_IPV4) {
141 ((struct sockaddr_in *)dst)->sin_family = AF_INET;
142 ((struct sockaddr_in *)dst)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
143 ((struct sockaddr_in *)dst)->sin_port = port;
144 } else if (smp->data.type == SMP_T_IPV6) {
145 ((struct sockaddr_in6 *)dst)->sin6_family = AF_INET6;
146 memcpy(&((struct sockaddr_in6 *)dst)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
147 ((struct sockaddr_in6 *)dst)->sin6_port = port;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200148 }
149 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200150
151 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200152 return ACT_RET_CONT;
153}
154
155/*
156 * Execute the "set-src-port" action. May be called from {tcp,http}request.
157 * We must test the sin_family before setting the port. If the address family
158 * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0"
159 * and the port is assigned.
160 */
161static enum act_return tcp_action_req_set_src_port(struct act_rule *rule, struct proxy *px,
162 struct session *sess, struct stream *s, int flags)
163{
164 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200165 struct sockaddr_storage *src;
166 struct sample *smp;
167
168 switch (rule->from) {
169 case ACT_F_TCP_REQ_CON:
170 cli_conn = objt_conn(sess->origin);
171 if (!cli_conn || !conn_get_src(cli_conn))
172 goto end;
173 src = cli_conn->src;
174 break;
175
176 case ACT_F_TCP_REQ_SES:
177 if (!sess_get_src(sess))
178 goto end;
179 src = sess->src;
180 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200181
Christopher Fauletd69377e2021-10-25 08:26:34 +0200182 case ACT_F_TCP_REQ_CNT:
183 case ACT_F_HTTP_REQ:
Christopher Faulet0de82722021-12-23 13:59:47 +0100184 if (!si_get_src(cs_si(s->csf)))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200185 goto end;
Christopher Faulet0de82722021-12-23 13:59:47 +0100186 src = cs_si(s->csf)->src;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200187 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200188
Christopher Fauletd69377e2021-10-25 08:26:34 +0200189 default:
190 goto end;
191 }
192
193 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT);
194 if (smp) {
195 if (src->ss_family == AF_INET6) {
196 ((struct sockaddr_in6 *)src)->sin6_port = htons(smp->data.u.sint);
197 } else {
198 if (src->ss_family != AF_INET) {
199 src->ss_family = AF_INET;
200 ((struct sockaddr_in *)src)->sin_addr.s_addr = 0;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200201 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200202 ((struct sockaddr_in *)src)->sin_port = htons(smp->data.u.sint);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200203 }
204 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200205
206 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200207 return ACT_RET_CONT;
208}
209
210/*
211 * Execute the "set-dst-port" action. May be called from {tcp,http}request.
212 * We must test the sin_family before setting the port. If the address family
213 * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0"
214 * and the port is assigned.
215 */
216static enum act_return tcp_action_req_set_dst_port(struct act_rule *rule, struct proxy *px,
217 struct session *sess, struct stream *s, int flags)
218{
219 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200220 struct sockaddr_storage *dst;
221 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200222
Christopher Fauletd69377e2021-10-25 08:26:34 +0200223 switch (rule->from) {
224 case ACT_F_TCP_REQ_CON:
225 cli_conn = objt_conn(sess->origin);
226 if (!cli_conn || !conn_get_dst(cli_conn))
227 goto end;
228 dst = cli_conn->dst;
229 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200230
Christopher Fauletd69377e2021-10-25 08:26:34 +0200231 case ACT_F_TCP_REQ_SES:
232 if (!sess_get_dst(sess))
233 goto end;
234 dst = sess->dst;
235 break;
236
237 case ACT_F_TCP_REQ_CNT:
238 case ACT_F_HTTP_REQ:
Christopher Faulet0de82722021-12-23 13:59:47 +0100239 if (!si_get_dst(cs_si(s->csf)))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200240 goto end;
Christopher Faulet0de82722021-12-23 13:59:47 +0100241 dst = cs_si(s->csf)->dst;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200242 break;
243
244 default:
245 goto end;
246 }
247
248 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT);
249 if (smp) {
250 if (dst->ss_family == AF_INET6) {
251 ((struct sockaddr_in6 *)dst)->sin6_port = htons(smp->data.u.sint);
252 } else {
253 if (dst->ss_family != AF_INET) {
254 dst->ss_family = AF_INET;
255 ((struct sockaddr_in *)dst)->sin_addr.s_addr = 0;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200256 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200257 ((struct sockaddr_in *)dst)->sin_port = htons(smp->data.u.sint);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200258 }
259 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200260
261 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200262 return ACT_RET_CONT;
263}
264
265/* Executes the "silent-drop" action. May be called from {tcp,http}{request,response} */
266static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct proxy *px,
267 struct session *sess, struct stream *strm, int flags)
268{
269 struct connection *conn = objt_conn(sess->origin);
270
271 if (!conn)
272 goto out;
273
274 if (!conn_ctrl_ready(conn))
275 goto out;
276
277#ifdef TCP_QUICKACK
278 /* drain is needed only to send the quick ACK */
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100279 conn_ctrl_drain(conn);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200280
281 /* re-enable quickack if it was disabled to ack all data and avoid
282 * retransmits from the client that might trigger a real reset.
283 */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200284 setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200285#endif
286 /* lingering must absolutely be disabled so that we don't send a
287 * shutdown(), this is critical to the TCP_REPAIR trick. When no stream
288 * is present, returning with ERR will cause lingering to be disabled.
289 */
290 if (strm)
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100291 strm->csf->si->flags |= SI_FL_NOLINGER;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200292
Willy Tarreaue2226792022-04-11 18:04:33 +0200293 if (conn->flags & CO_FL_FDLESS)
294 goto out;
295
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200296 /* We're on the client-facing side, we must force to disable lingering to
297 * ensure we will use an RST exclusively and kill any pending data.
298 */
Willy Tarreaub41a6e92021-04-06 17:49:19 +0200299 HA_ATOMIC_OR(&fdtab[conn->handle.fd].state, FD_LINGER_RISK);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200300
301#ifdef TCP_REPAIR
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200302 if (setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_REPAIR, &one, sizeof(one)) == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200303 /* socket will be quiet now */
304 goto out;
305 }
306#endif
307 /* either TCP_REPAIR is not defined or it failed (eg: permissions).
308 * Let's fall back on the TTL trick, though it only works for routed
309 * network and has no effect on local net.
310 */
311#ifdef IP_TTL
Willy Tarreauab79ee82021-03-30 17:23:50 +0200312 if (conn->src && conn->src->ss_family == AF_INET)
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200313 setsockopt(conn->handle.fd, IPPROTO_IP, IP_TTL, &one, sizeof(one));
Willy Tarreauab79ee82021-03-30 17:23:50 +0200314#endif
315#ifdef IPV6_UNICAST_HOPS
Willy Tarreauda231952021-03-31 08:29:27 +0200316 if (conn->src && conn->src->ss_family == AF_INET6)
317 setsockopt(conn->handle.fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one));
318#endif
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200319 out:
320 /* kill the stream if any */
321 if (strm) {
322 channel_abort(&strm->req);
323 channel_abort(&strm->res);
324 strm->req.analysers &= AN_REQ_FLT_END;
325 strm->res.analysers &= AN_RES_FLT_END;
326 if (strm->flags & SF_BE_ASSIGNED)
Willy Tarreau4781b152021-04-06 13:53:36 +0200327 _HA_ATOMIC_INC(&strm->be->be_counters.denied_req);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200328 if (!(strm->flags & SF_ERR_MASK))
329 strm->flags |= SF_ERR_PRXCOND;
330 if (!(strm->flags & SF_FINST_MASK))
331 strm->flags |= SF_FINST_R;
332 }
333
Willy Tarreau4781b152021-04-06 13:53:36 +0200334 _HA_ATOMIC_INC(&sess->fe->fe_counters.denied_req);
William Lallemand36119de2021-03-08 15:26:48 +0100335 if (sess->listener && sess->listener->counters)
Willy Tarreau4781b152021-04-06 13:53:36 +0200336 _HA_ATOMIC_INC(&sess->listener->counters->denied_req);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200337
338 return ACT_RET_ABRT;
339}
340
Christopher Faulet469c06c2021-06-25 15:11:35 +0200341
David Carlierbae4cb22021-07-03 10:15:15 +0100342#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
Christopher Faulet469c06c2021-06-25 15:11:35 +0200343static enum act_return tcp_action_set_mark(struct act_rule *rule, struct proxy *px,
344 struct session *sess, struct stream *s, int flags)
345{
346 conn_set_mark(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
347 return ACT_RET_CONT;
348}
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200349#endif
Christopher Faulet469c06c2021-06-25 15:11:35 +0200350
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200351#ifdef IP_TOS
Christopher Faulet469c06c2021-06-25 15:11:35 +0200352static enum act_return tcp_action_set_tos(struct act_rule *rule, struct proxy *px,
353 struct session *sess, struct stream *s, int flags)
354{
355 conn_set_tos(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
356 return ACT_RET_CONT;
357}
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200358#endif
Christopher Faulet469c06c2021-06-25 15:11:35 +0200359
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200360/* parse "set-{src,dst}[-port]" action */
361static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struct proxy *px,
362 struct act_rule *rule, char **err)
363{
364 int cur_arg;
365 struct sample_expr *expr;
366 unsigned int where;
367
368 cur_arg = *orig_arg;
369 expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
370 if (!expr)
371 return ACT_RET_PRS_ERR;
372
373 where = 0;
374 if (px->cap & PR_CAP_FE)
375 where |= SMP_VAL_FE_HRQ_HDR;
376 if (px->cap & PR_CAP_BE)
377 where |= SMP_VAL_BE_HRQ_HDR;
378
379 if (!(expr->fetch->val & where)) {
380 memprintf(err,
381 "fetch method '%s' extracts information from '%s', none of which is available here",
382 args[cur_arg-1], sample_src_names(expr->fetch->use));
383 free(expr);
384 return ACT_RET_PRS_ERR;
385 }
386 rule->arg.expr = expr;
387 rule->action = ACT_CUSTOM;
388
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100389 if (strcmp(args[*orig_arg - 1], "set-src") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200390 rule->action_ptr = tcp_action_req_set_src;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100391 } else if (strcmp(args[*orig_arg - 1], "set-src-port") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200392 rule->action_ptr = tcp_action_req_set_src_port;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100393 } else if (strcmp(args[*orig_arg - 1], "set-dst") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200394 rule->action_ptr = tcp_action_req_set_dst;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100395 } else if (strcmp(args[*orig_arg - 1], "set-dst-port") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200396 rule->action_ptr = tcp_action_req_set_dst_port;
397 } else {
398 return ACT_RET_PRS_ERR;
399 }
400
401 (*orig_arg)++;
402
Christopher Faulet469c06c2021-06-25 15:11:35 +0200403 return ACT_RET_PRS_OK;
404}
405
406
407/* Parse a "set-mark" action. It takes the MARK value as argument. It returns
408 * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
409 */
410static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, struct proxy *px,
411 struct act_rule *rule, char **err)
412{
David Carlierbae4cb22021-07-03 10:15:15 +0100413#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
Christopher Faulet469c06c2021-06-25 15:11:35 +0200414 char *endp;
415 unsigned int mark;
416
417 if (!*args[*cur_arg]) {
418 memprintf(err, "expects exactly 1 argument (integer/hex value)");
419 return ACT_RET_PRS_ERR;
420 }
421 mark = strtoul(args[*cur_arg], &endp, 0);
422 if (endp && *endp != '\0') {
423 memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
424 return ACT_RET_PRS_ERR;
425 }
426
427 (*cur_arg)++;
428
429 /* Register processing function. */
430 rule->action_ptr = tcp_action_set_mark;
431 rule->action = ACT_CUSTOM;
432 rule->arg.act.p[0] = (void *)(uintptr_t)mark;
433 global.last_checks |= LSTCHK_NETADM;
434 return ACT_RET_PRS_OK;
435#else
David Carlierbae4cb22021-07-03 10:15:15 +0100436 memprintf(err, "not supported on this platform (SO_MARK|SO_USER_COOKIE|SO_RTABLE undefined)");
Christopher Faulet469c06c2021-06-25 15:11:35 +0200437 return ACT_RET_PRS_ERR;
438#endif
439}
440
441
442/* Parse a "set-tos" action. It takes the TOS value as argument. It returns
443 * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
444 */
445static enum act_parse_ret tcp_parse_set_tos(const char **args, int *cur_arg, struct proxy *px,
446 struct act_rule *rule, char **err)
447{
448#ifdef IP_TOS
449 char *endp;
450 int tos;
451
452 if (!*args[*cur_arg]) {
453 memprintf(err, "expects exactly 1 argument (integer/hex value)");
454 return ACT_RET_PRS_ERR;
455 }
456 tos = strtol(args[*cur_arg], &endp, 0);
457 if (endp && *endp != '\0') {
458 memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
459 return ACT_RET_PRS_ERR;
460 }
461
462 (*cur_arg)++;
463
464 /* Register processing function. */
465 rule->action_ptr = tcp_action_set_tos;
466 rule->action = ACT_CUSTOM;
467 rule->arg.act.p[0] = (void *)(uintptr_t)tos;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200468 return ACT_RET_PRS_OK;
Christopher Faulet469c06c2021-06-25 15:11:35 +0200469#else
470 memprintf(err, "not supported on this platform (IP_TOS undefined)");
471 return ACT_RET_PRS_ERR;
472#endif
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200473}
474
475
476/* Parse a "silent-drop" action. It takes no argument. It returns ACT_RET_PRS_OK on
477 * success, ACT_RET_PRS_ERR on error.
478 */
479static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *orig_arg, struct proxy *px,
480 struct act_rule *rule, char **err)
481{
482 rule->action = ACT_CUSTOM;
483 rule->action_ptr = tcp_exec_action_silent_drop;
484 return ACT_RET_PRS_OK;
485}
486
487
488static struct action_kw_list tcp_req_conn_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200489 { "set-dst" , tcp_parse_set_src_dst },
490 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200491 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200492 { "set-src", tcp_parse_set_src_dst },
493 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200494 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200495 { "silent-drop", tcp_parse_silent_drop },
496 { /* END */ }
497}};
498
499INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions);
500
501static struct action_kw_list tcp_req_sess_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200502 { "set-dst" , tcp_parse_set_src_dst },
503 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200504 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200505 { "set-src", tcp_parse_set_src_dst },
506 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200507 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200508 { "silent-drop", tcp_parse_silent_drop },
509 { /* END */ }
510}};
511
512INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions);
513
514static struct action_kw_list tcp_req_cont_actions = {ILH, {
Christopher Faulet1e83b702021-06-23 12:07:21 +0200515 { "set-src", tcp_parse_set_src_dst },
516 { "set-src-port", tcp_parse_set_src_dst },
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200517 { "set-dst" , tcp_parse_set_src_dst },
518 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200519 { "set-mark", tcp_parse_set_mark },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200520 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200521 { "silent-drop", tcp_parse_silent_drop },
522 { /* END */ }
523}};
524
525INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions);
526
527static struct action_kw_list tcp_res_cont_actions = {ILH, {
Christopher Faulet469c06c2021-06-25 15:11:35 +0200528 { "set-mark", tcp_parse_set_mark },
529 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200530 { "silent-drop", tcp_parse_silent_drop },
531 { /* END */ }
532}};
533
534INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions);
535
536static struct action_kw_list http_req_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200537 { "set-dst", tcp_parse_set_src_dst },
538 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200539 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200540 { "set-src", tcp_parse_set_src_dst },
541 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200542 { "set-tos", tcp_parse_set_tos },
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200543 { "silent-drop", tcp_parse_silent_drop },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200544 { /* END */ }
545}};
546
547INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
548
549static struct action_kw_list http_res_actions = {ILH, {
Christopher Faulet469c06c2021-06-25 15:11:35 +0200550 { "set-mark", tcp_parse_set_mark },
551 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200552 { "silent-drop", tcp_parse_silent_drop },
553 { /* END */ }
554}};
555
556INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
557
558
559/*
560 * Local variables:
561 * c-indent-level: 8
562 * c-basic-offset: 8
563 * End:
564 */