blob: 05ed05695b759b16cfa48a0f8ab0af108c563e1d [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>
Willy Tarreauaeae66c2020-08-28 11:03:28 +020015#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <time.h>
19
20#include <sys/param.h>
21#include <sys/socket.h>
22#include <sys/types.h>
23
24#include <netinet/tcp.h>
25#include <netinet/in.h>
26
27#include <haproxy/action-t.h>
28#include <haproxy/api.h>
29#include <haproxy/arg.h>
30#include <haproxy/channel.h>
31#include <haproxy/connection.h>
32#include <haproxy/global.h>
33#include <haproxy/http_rules.h>
34#include <haproxy/proto_tcp.h>
35#include <haproxy/proxy-t.h>
36#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020037#include <haproxy/sc_strm.h>
Christopher Fauletd69377e2021-10-25 08:26:34 +020038#include <haproxy/session.h>
Willy Tarreauaeae66c2020-08-28 11:03:28 +020039#include <haproxy/tcp_rules.h>
40#include <haproxy/tools.h>
41
42/*
43 * Execute the "set-src" action. May be called from {tcp,http}request.
44 * It only changes the address and tries to preserve the original port. If the
45 * previous family was neither AF_INET nor AF_INET6, the port is set to zero.
46 */
47static enum act_return tcp_action_req_set_src(struct act_rule *rule, struct proxy *px,
48 struct session *sess, struct stream *s, int flags)
49{
50 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +020051 struct sockaddr_storage *src;
52 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020053
Christopher Fauletd69377e2021-10-25 08:26:34 +020054 switch (rule->from) {
55 case ACT_F_TCP_REQ_CON:
56 cli_conn = objt_conn(sess->origin);
57 if (!cli_conn || !conn_get_src(cli_conn))
58 goto end;
59 src = cli_conn->src;
60 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020061
Christopher Fauletd69377e2021-10-25 08:26:34 +020062 case ACT_F_TCP_REQ_SES:
63 if (!sess_get_src(sess))
64 goto end;
65 src = sess->src;
66 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020067
Christopher Fauletd69377e2021-10-25 08:26:34 +020068 case ACT_F_TCP_REQ_CNT:
69 case ACT_F_HTTP_REQ:
Willy Tarreaud68ff012022-05-27 08:57:21 +020070 if (!sc_get_src(s->scf))
Christopher Fauletd69377e2021-10-25 08:26:34 +020071 goto end;
Willy Tarreau7cb9e6c2022-05-17 19:40:40 +020072 src = s->scf->src;
Christopher Fauletd69377e2021-10-25 08:26:34 +020073 break;
74
75 default:
76 goto end;
77 }
78
79 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR);
80 if (smp) {
81 int port = get_net_port(src);
82
83 if (smp->data.type == SMP_T_IPV4) {
84 ((struct sockaddr_in *)src)->sin_family = AF_INET;
85 ((struct sockaddr_in *)src)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
86 ((struct sockaddr_in *)src)->sin_port = port;
87 } else if (smp->data.type == SMP_T_IPV6) {
88 ((struct sockaddr_in6 *)src)->sin6_family = AF_INET6;
89 memcpy(&((struct sockaddr_in6 *)src)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
90 ((struct sockaddr_in6 *)src)->sin6_port = port;
Willy Tarreauaeae66c2020-08-28 11:03:28 +020091 }
Willy Tarreauaeae66c2020-08-28 11:03:28 +020092 }
Christopher Fauletd69377e2021-10-25 08:26:34 +020093
94 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +020095 return ACT_RET_CONT;
96}
97
98/*
99 * Execute the "set-dst" action. May be called from {tcp,http}request.
100 * It only changes the address and tries to preserve the original port. If the
101 * previous family was neither AF_INET nor AF_INET6, the port is set to zero.
102 */
103static enum act_return tcp_action_req_set_dst(struct act_rule *rule, struct proxy *px,
104 struct session *sess, struct stream *s, int flags)
105{
106 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200107 struct sockaddr_storage *dst;
108 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200109
Christopher Fauletd69377e2021-10-25 08:26:34 +0200110 switch (rule->from) {
111 case ACT_F_TCP_REQ_CON:
112 cli_conn = objt_conn(sess->origin);
113 if (!cli_conn || !conn_get_dst(cli_conn))
114 goto end;
115 dst = cli_conn->dst;
116 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200117
Christopher Fauletd69377e2021-10-25 08:26:34 +0200118 case ACT_F_TCP_REQ_SES:
119 if (!sess_get_dst(sess))
120 goto end;
121 dst = sess->dst;
122 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200123
Christopher Fauletd69377e2021-10-25 08:26:34 +0200124 case ACT_F_TCP_REQ_CNT:
125 case ACT_F_HTTP_REQ:
Willy Tarreaud68ff012022-05-27 08:57:21 +0200126 if (!sc_get_dst(s->scf))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200127 goto end;
Willy Tarreau7cb9e6c2022-05-17 19:40:40 +0200128 dst = s->scf->dst;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200129 break;
130
131 default:
132 goto end;
133 }
134
135 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_ADDR);
136 if (smp) {
137 int port = get_net_port(dst);
138
139 if (smp->data.type == SMP_T_IPV4) {
140 ((struct sockaddr_in *)dst)->sin_family = AF_INET;
141 ((struct sockaddr_in *)dst)->sin_addr.s_addr = smp->data.u.ipv4.s_addr;
142 ((struct sockaddr_in *)dst)->sin_port = port;
143 } else if (smp->data.type == SMP_T_IPV6) {
144 ((struct sockaddr_in6 *)dst)->sin6_family = AF_INET6;
145 memcpy(&((struct sockaddr_in6 *)dst)->sin6_addr, &smp->data.u.ipv6, sizeof(struct in6_addr));
146 ((struct sockaddr_in6 *)dst)->sin6_port = port;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200147 }
148 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200149
150 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200151 return ACT_RET_CONT;
152}
153
154/*
155 * Execute the "set-src-port" action. May be called from {tcp,http}request.
156 * We must test the sin_family before setting the port. If the address family
157 * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0"
158 * and the port is assigned.
159 */
160static enum act_return tcp_action_req_set_src_port(struct act_rule *rule, struct proxy *px,
161 struct session *sess, struct stream *s, int flags)
162{
163 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200164 struct sockaddr_storage *src;
165 struct sample *smp;
166
167 switch (rule->from) {
168 case ACT_F_TCP_REQ_CON:
169 cli_conn = objt_conn(sess->origin);
170 if (!cli_conn || !conn_get_src(cli_conn))
171 goto end;
172 src = cli_conn->src;
173 break;
174
175 case ACT_F_TCP_REQ_SES:
176 if (!sess_get_src(sess))
177 goto end;
178 src = sess->src;
179 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200180
Christopher Fauletd69377e2021-10-25 08:26:34 +0200181 case ACT_F_TCP_REQ_CNT:
182 case ACT_F_HTTP_REQ:
Willy Tarreaud68ff012022-05-27 08:57:21 +0200183 if (!sc_get_src(s->scf))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200184 goto end;
Willy Tarreau7cb9e6c2022-05-17 19:40:40 +0200185 src = s->scf->src;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200186 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200187
Christopher Fauletd69377e2021-10-25 08:26:34 +0200188 default:
189 goto end;
190 }
191
192 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT);
193 if (smp) {
194 if (src->ss_family == AF_INET6) {
195 ((struct sockaddr_in6 *)src)->sin6_port = htons(smp->data.u.sint);
196 } else {
197 if (src->ss_family != AF_INET) {
198 src->ss_family = AF_INET;
199 ((struct sockaddr_in *)src)->sin_addr.s_addr = 0;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200200 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200201 ((struct sockaddr_in *)src)->sin_port = htons(smp->data.u.sint);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200202 }
203 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200204
205 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200206 return ACT_RET_CONT;
207}
208
209/*
210 * Execute the "set-dst-port" action. May be called from {tcp,http}request.
211 * We must test the sin_family before setting the port. If the address family
212 * is neither AF_INET nor AF_INET6, the address is forced to AF_INET "0.0.0.0"
213 * and the port is assigned.
214 */
215static enum act_return tcp_action_req_set_dst_port(struct act_rule *rule, struct proxy *px,
216 struct session *sess, struct stream *s, int flags)
217{
218 struct connection *cli_conn;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200219 struct sockaddr_storage *dst;
220 struct sample *smp;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200221
Christopher Fauletd69377e2021-10-25 08:26:34 +0200222 switch (rule->from) {
223 case ACT_F_TCP_REQ_CON:
224 cli_conn = objt_conn(sess->origin);
225 if (!cli_conn || !conn_get_dst(cli_conn))
226 goto end;
227 dst = cli_conn->dst;
228 break;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200229
Christopher Fauletd69377e2021-10-25 08:26:34 +0200230 case ACT_F_TCP_REQ_SES:
231 if (!sess_get_dst(sess))
232 goto end;
233 dst = sess->dst;
234 break;
235
236 case ACT_F_TCP_REQ_CNT:
237 case ACT_F_HTTP_REQ:
Willy Tarreaud68ff012022-05-27 08:57:21 +0200238 if (!sc_get_dst(s->scf))
Christopher Fauletd69377e2021-10-25 08:26:34 +0200239 goto end;
Willy Tarreau7cb9e6c2022-05-17 19:40:40 +0200240 dst = s->scf->dst;
Christopher Fauletd69377e2021-10-25 08:26:34 +0200241 break;
242
243 default:
244 goto end;
245 }
246
247 smp = sample_fetch_as_type(px, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, rule->arg.expr, SMP_T_SINT);
248 if (smp) {
249 if (dst->ss_family == AF_INET6) {
250 ((struct sockaddr_in6 *)dst)->sin6_port = htons(smp->data.u.sint);
251 } else {
252 if (dst->ss_family != AF_INET) {
253 dst->ss_family = AF_INET;
254 ((struct sockaddr_in *)dst)->sin_addr.s_addr = 0;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200255 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200256 ((struct sockaddr_in *)dst)->sin_port = htons(smp->data.u.sint);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200257 }
258 }
Christopher Fauletd69377e2021-10-25 08:26:34 +0200259
260 end:
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200261 return ACT_RET_CONT;
262}
263
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100264/* Executes the "silent-drop" action. May be called from {tcp,http}{request,response}.
265 * If rule->arg.act.p[0] is 0, TCP_REPAIR is tried first, with a fallback to
266 * sending a RST with TTL 1 towards the client. If it is [1-255], we will skip
267 * TCP_REPAIR and prepare the socket to send a RST with the requested TTL when
268 * the connection is killed by channel_abort().
269 */
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200270static enum act_return tcp_exec_action_silent_drop(struct act_rule *rule, struct proxy *px,
271 struct session *sess, struct stream *strm, int flags)
272{
273 struct connection *conn = objt_conn(sess->origin);
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100274 unsigned int ttl __maybe_unused = (uintptr_t)rule->arg.act.p[0];
275 char tcp_repair_enabled __maybe_unused;
276
277 if (ttl == 0) {
278 tcp_repair_enabled = 1;
279 ttl = 1;
280 } else {
281 tcp_repair_enabled = 0;
282 }
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200283
284 if (!conn)
285 goto out;
286
287 if (!conn_ctrl_ready(conn))
288 goto out;
289
290#ifdef TCP_QUICKACK
291 /* drain is needed only to send the quick ACK */
Willy Tarreau2ded48d2020-12-11 16:20:34 +0100292 conn_ctrl_drain(conn);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200293
294 /* re-enable quickack if it was disabled to ack all data and avoid
295 * retransmits from the client that might trigger a real reset.
296 */
Willy Tarreau4bfc6632021-03-31 08:45:47 +0200297 setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200298#endif
299 /* lingering must absolutely be disabled so that we don't send a
300 * shutdown(), this is critical to the TCP_REPAIR trick. When no stream
301 * is present, returning with ERR will cause lingering to be disabled.
302 */
303 if (strm)
Willy Tarreaucb041662022-05-17 19:44:42 +0200304 strm->scf->flags |= SC_FL_NOLINGER;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200305
Willy Tarreaue2226792022-04-11 18:04:33 +0200306 if (conn->flags & CO_FL_FDLESS)
307 goto out;
308
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200309 /* We're on the client-facing side, we must force to disable lingering to
310 * ensure we will use an RST exclusively and kill any pending data.
311 */
Willy Tarreaub41a6e92021-04-06 17:49:19 +0200312 HA_ATOMIC_OR(&fdtab[conn->handle.fd].state, FD_LINGER_RISK);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200313
314#ifdef TCP_REPAIR
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100315 /* try to put socket in repair mode if sending a RST was not requested by
316 * config. this often fails due to missing permissions (CAP_NET_ADMIN capability)
317 */
318 if (tcp_repair_enabled && (setsockopt(conn->handle.fd, IPPROTO_TCP, TCP_REPAIR, &one, sizeof(one)) == 0)) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200319 /* socket will be quiet now */
320 goto out;
321 }
322#endif
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100323
324 /* Either TCP_REPAIR is not defined, it failed (eg: permissions), or was
325 * not executed because a RST with a specific TTL was requested to be sent.
326 * Set the TTL of the client connection before the connection is killed
327 * by channel_abort and a RST packet will be emitted by the TCP/IP stack.
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200328 */
329#ifdef IP_TTL
Willy Tarreauab79ee82021-03-30 17:23:50 +0200330 if (conn->src && conn->src->ss_family == AF_INET)
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100331 setsockopt(conn->handle.fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
Willy Tarreauab79ee82021-03-30 17:23:50 +0200332#endif
333#ifdef IPV6_UNICAST_HOPS
Willy Tarreauda231952021-03-31 08:29:27 +0200334 if (conn->src && conn->src->ss_family == AF_INET6)
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100335 setsockopt(conn->handle.fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl));
Willy Tarreauda231952021-03-31 08:29:27 +0200336#endif
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200337 out:
338 /* kill the stream if any */
339 if (strm) {
Christopher Faulet7eb837d2023-04-13 15:22:29 +0200340 stream_abort(strm);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200341 strm->req.analysers &= AN_REQ_FLT_END;
342 strm->res.analysers &= AN_RES_FLT_END;
343 if (strm->flags & SF_BE_ASSIGNED)
Willy Tarreau4781b152021-04-06 13:53:36 +0200344 _HA_ATOMIC_INC(&strm->be->be_counters.denied_req);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200345 if (!(strm->flags & SF_ERR_MASK))
346 strm->flags |= SF_ERR_PRXCOND;
347 if (!(strm->flags & SF_FINST_MASK))
348 strm->flags |= SF_FINST_R;
349 }
350
Willy Tarreau4781b152021-04-06 13:53:36 +0200351 _HA_ATOMIC_INC(&sess->fe->fe_counters.denied_req);
William Lallemand36119de2021-03-08 15:26:48 +0100352 if (sess->listener && sess->listener->counters)
Willy Tarreau4781b152021-04-06 13:53:36 +0200353 _HA_ATOMIC_INC(&sess->listener->counters->denied_req);
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200354
355 return ACT_RET_ABRT;
356}
357
Christopher Faulet469c06c2021-06-25 15:11:35 +0200358
David Carlierbae4cb22021-07-03 10:15:15 +0100359#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
Christopher Faulet469c06c2021-06-25 15:11:35 +0200360static enum act_return tcp_action_set_mark(struct act_rule *rule, struct proxy *px,
361 struct session *sess, struct stream *s, int flags)
362{
363 conn_set_mark(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
364 return ACT_RET_CONT;
365}
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200366#endif
Christopher Faulet469c06c2021-06-25 15:11:35 +0200367
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200368#ifdef IP_TOS
Christopher Faulet469c06c2021-06-25 15:11:35 +0200369static enum act_return tcp_action_set_tos(struct act_rule *rule, struct proxy *px,
370 struct session *sess, struct stream *s, int flags)
371{
372 conn_set_tos(objt_conn(sess->origin), (uintptr_t)rule->arg.act.p[0]);
373 return ACT_RET_CONT;
374}
Willy Tarreau5bbfff12021-06-28 07:12:22 +0200375#endif
Christopher Faulet469c06c2021-06-25 15:11:35 +0200376
William Lallemand0164a402022-05-06 16:54:09 +0200377/*
378 * Release the sample expr when releasing a set src/dst action
379 */
380static void release_set_src_dst_action(struct act_rule *rule)
381{
382 release_sample_expr(rule->arg.expr);
383}
384
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200385/* parse "set-{src,dst}[-port]" action */
386static enum act_parse_ret tcp_parse_set_src_dst(const char **args, int *orig_arg, struct proxy *px,
387 struct act_rule *rule, char **err)
388{
389 int cur_arg;
390 struct sample_expr *expr;
391 unsigned int where;
392
393 cur_arg = *orig_arg;
394 expr = sample_parse_expr((char **)args, &cur_arg, px->conf.args.file, px->conf.args.line, err, &px->conf.args, NULL);
395 if (!expr)
396 return ACT_RET_PRS_ERR;
397
398 where = 0;
399 if (px->cap & PR_CAP_FE)
400 where |= SMP_VAL_FE_HRQ_HDR;
401 if (px->cap & PR_CAP_BE)
402 where |= SMP_VAL_BE_HRQ_HDR;
403
404 if (!(expr->fetch->val & where)) {
405 memprintf(err,
406 "fetch method '%s' extracts information from '%s', none of which is available here",
407 args[cur_arg-1], sample_src_names(expr->fetch->use));
408 free(expr);
409 return ACT_RET_PRS_ERR;
410 }
411 rule->arg.expr = expr;
412 rule->action = ACT_CUSTOM;
413
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100414 if (strcmp(args[*orig_arg - 1], "set-src") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200415 rule->action_ptr = tcp_action_req_set_src;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100416 } else if (strcmp(args[*orig_arg - 1], "set-src-port") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200417 rule->action_ptr = tcp_action_req_set_src_port;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100418 } else if (strcmp(args[*orig_arg - 1], "set-dst") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200419 rule->action_ptr = tcp_action_req_set_dst;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100420 } else if (strcmp(args[*orig_arg - 1], "set-dst-port") == 0) {
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200421 rule->action_ptr = tcp_action_req_set_dst_port;
422 } else {
423 return ACT_RET_PRS_ERR;
424 }
425
William Lallemand0164a402022-05-06 16:54:09 +0200426 rule->release_ptr = release_set_src_dst_action;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200427 (*orig_arg)++;
428
Christopher Faulet469c06c2021-06-25 15:11:35 +0200429 return ACT_RET_PRS_OK;
430}
431
432
433/* Parse a "set-mark" action. It takes the MARK value as argument. It returns
434 * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
435 */
436static enum act_parse_ret tcp_parse_set_mark(const char **args, int *cur_arg, struct proxy *px,
437 struct act_rule *rule, char **err)
438{
David Carlierbae4cb22021-07-03 10:15:15 +0100439#if defined(SO_MARK) || defined(SO_USER_COOKIE) || defined(SO_RTABLE)
Christopher Faulet469c06c2021-06-25 15:11:35 +0200440 char *endp;
441 unsigned int mark;
442
443 if (!*args[*cur_arg]) {
444 memprintf(err, "expects exactly 1 argument (integer/hex value)");
445 return ACT_RET_PRS_ERR;
446 }
447 mark = strtoul(args[*cur_arg], &endp, 0);
448 if (endp && *endp != '\0') {
449 memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
450 return ACT_RET_PRS_ERR;
451 }
452
453 (*cur_arg)++;
454
455 /* Register processing function. */
456 rule->action_ptr = tcp_action_set_mark;
457 rule->action = ACT_CUSTOM;
458 rule->arg.act.p[0] = (void *)(uintptr_t)mark;
459 global.last_checks |= LSTCHK_NETADM;
460 return ACT_RET_PRS_OK;
461#else
David Carlierbae4cb22021-07-03 10:15:15 +0100462 memprintf(err, "not supported on this platform (SO_MARK|SO_USER_COOKIE|SO_RTABLE undefined)");
Christopher Faulet469c06c2021-06-25 15:11:35 +0200463 return ACT_RET_PRS_ERR;
464#endif
465}
466
467
468/* Parse a "set-tos" action. It takes the TOS value as argument. It returns
469 * ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
470 */
471static enum act_parse_ret tcp_parse_set_tos(const char **args, int *cur_arg, struct proxy *px,
472 struct act_rule *rule, char **err)
473{
474#ifdef IP_TOS
475 char *endp;
476 int tos;
477
478 if (!*args[*cur_arg]) {
479 memprintf(err, "expects exactly 1 argument (integer/hex value)");
480 return ACT_RET_PRS_ERR;
481 }
482 tos = strtol(args[*cur_arg], &endp, 0);
483 if (endp && *endp != '\0') {
484 memprintf(err, "invalid character starting at '%s' (integer/hex value expected)", endp);
485 return ACT_RET_PRS_ERR;
486 }
487
488 (*cur_arg)++;
489
490 /* Register processing function. */
491 rule->action_ptr = tcp_action_set_tos;
492 rule->action = ACT_CUSTOM;
493 rule->arg.act.p[0] = (void *)(uintptr_t)tos;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200494 return ACT_RET_PRS_OK;
Christopher Faulet469c06c2021-06-25 15:11:35 +0200495#else
496 memprintf(err, "not supported on this platform (IP_TOS undefined)");
497 return ACT_RET_PRS_ERR;
498#endif
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200499}
500
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100501/* Parse a "silent-drop" action. It may take 2 optional arguments to define a
502 * "rst-ttl" parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR
503 * on error.
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200504 */
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100505static enum act_parse_ret tcp_parse_silent_drop(const char **args, int *cur_arg, struct proxy *px,
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200506 struct act_rule *rule, char **err)
507{
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100508 unsigned int rst_ttl = 0;
509 char *endp;
510
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200511 rule->action = ACT_CUSTOM;
512 rule->action_ptr = tcp_exec_action_silent_drop;
Mathias Weiersmuellerd9b71742022-11-19 00:07:56 +0100513
514 if (strcmp(args[*cur_arg], "rst-ttl") == 0) {
515 if (!*args[*cur_arg + 1]) {
516 memprintf(err, "missing rst-ttl value\n");
517 return ACT_RET_PRS_ERR;
518 }
519
520 rst_ttl = (unsigned int)strtoul(args[*cur_arg + 1], &endp, 0);
521
522 if (endp && *endp != '\0') {
523 memprintf(err, "invalid character starting at '%s' (value 1-255 expected)\n",
524 endp);
525 return ACT_RET_PRS_ERR;
526 }
527 if ((rst_ttl == 0) || (rst_ttl > 255) ) {
528 memprintf(err, "valid rst-ttl values are [1-255]\n");
529 return ACT_RET_PRS_ERR;
530 }
531
532 *cur_arg += 2;
533 }
534
535 rule->arg.act.p[0] = (void *)(uintptr_t)rst_ttl;
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200536 return ACT_RET_PRS_OK;
537}
538
539
540static struct action_kw_list tcp_req_conn_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200541 { "set-dst" , tcp_parse_set_src_dst },
542 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200543 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200544 { "set-src", tcp_parse_set_src_dst },
545 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200546 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200547 { "silent-drop", tcp_parse_silent_drop },
548 { /* END */ }
549}};
550
551INITCALL1(STG_REGISTER, tcp_req_conn_keywords_register, &tcp_req_conn_actions);
552
553static struct action_kw_list tcp_req_sess_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200554 { "set-dst" , tcp_parse_set_src_dst },
555 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200556 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200557 { "set-src", tcp_parse_set_src_dst },
558 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200559 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200560 { "silent-drop", tcp_parse_silent_drop },
561 { /* END */ }
562}};
563
564INITCALL1(STG_REGISTER, tcp_req_sess_keywords_register, &tcp_req_sess_actions);
565
566static struct action_kw_list tcp_req_cont_actions = {ILH, {
Christopher Faulet1e83b702021-06-23 12:07:21 +0200567 { "set-src", tcp_parse_set_src_dst },
568 { "set-src-port", tcp_parse_set_src_dst },
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200569 { "set-dst" , tcp_parse_set_src_dst },
570 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200571 { "set-mark", tcp_parse_set_mark },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200572 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200573 { "silent-drop", tcp_parse_silent_drop },
574 { /* END */ }
575}};
576
577INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_cont_actions);
578
579static struct action_kw_list tcp_res_cont_actions = {ILH, {
Christopher Faulet469c06c2021-06-25 15:11:35 +0200580 { "set-mark", tcp_parse_set_mark },
581 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200582 { "silent-drop", tcp_parse_silent_drop },
583 { /* END */ }
584}};
585
586INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_cont_actions);
587
588static struct action_kw_list http_req_actions = {ILH, {
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200589 { "set-dst", tcp_parse_set_src_dst },
590 { "set-dst-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200591 { "set-mark", tcp_parse_set_mark },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200592 { "set-src", tcp_parse_set_src_dst },
593 { "set-src-port", tcp_parse_set_src_dst },
Christopher Faulet469c06c2021-06-25 15:11:35 +0200594 { "set-tos", tcp_parse_set_tos },
Christopher Fauletee9c98d2021-06-25 15:18:33 +0200595 { "silent-drop", tcp_parse_silent_drop },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200596 { /* END */ }
597}};
598
599INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_actions);
600
601static struct action_kw_list http_res_actions = {ILH, {
Christopher Faulet469c06c2021-06-25 15:11:35 +0200602 { "set-mark", tcp_parse_set_mark },
603 { "set-tos", tcp_parse_set_tos },
Willy Tarreauaeae66c2020-08-28 11:03:28 +0200604 { "silent-drop", tcp_parse_silent_drop },
605 { /* END */ }
606}};
607
608INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_actions);
609
610
611/*
612 * Local variables:
613 * c-indent-level: 8
614 * c-basic-offset: 8
615 * End:
616 */