blob: ee66ed1626cc9e28884dd064a126f05eef4ba97e [file] [log] [blame]
Willy Tarreau8987e7a2020-08-28 11:37:21 +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/* this is to have tcp_info defined on systems using musl
14 * library, such as Alpine Linux.
15 */
16#define _GNU_SOURCE
17
18#include <ctype.h>
19#include <errno.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <time.h>
24
25#include <sys/param.h>
26#include <sys/socket.h>
27#include <sys/types.h>
28
29#include <netinet/tcp.h>
30#include <netinet/in.h>
31
32#include <haproxy/api.h>
33#include <haproxy/arg.h>
34#include <haproxy/connection.h>
Willy Tarreau6cd007d2021-10-06 19:01:21 +020035#include <haproxy/errors.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020036#include <haproxy/global.h>
37#include <haproxy/listener-t.h>
38#include <haproxy/namespace.h>
39#include <haproxy/proxy-t.h>
40#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020041#include <haproxy/sc_strm.h>
Christopher Fauletc03be1a2021-10-25 08:01:20 +020042#include <haproxy/session.h>
Willy Tarreau8987e7a2020-08-28 11:37:21 +020043#include <haproxy/tools.h>
44
Christopher Faulet7d081f02021-04-15 09:38:37 +020045/* Fetch the connection's source IPv4/IPv6 address. Depending on the keyword, it
46 * may be the frontend or the backend connection.
Willy Tarreau8987e7a2020-08-28 11:37:21 +020047 */
48static int
49smp_fetch_src(const struct arg *args, struct sample *smp, const char *kw, void *private)
50{
Christopher Fauletc03be1a2021-10-25 08:01:20 +020051 const struct sockaddr_storage *src = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +020052
Christopher Faulet888cd702021-10-25 16:58:50 +020053 if (kw[0] == 'b') { /* bc_src */
Christopher Fauletc03be1a2021-10-25 08:01:20 +020054 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +020055 ? sc_conn(__objt_check(smp->sess->origin)->sc)
Willy Tarreaufd9417b2022-05-18 16:23:22 +020056 : (smp->strm ? sc_conn(smp->strm->scb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +020057 if (conn && conn_get_src(conn))
58 src = conn_src(conn);
59 }
Christopher Faulet888cd702021-10-25 16:58:50 +020060 else if (kw[0] == 'f') { /* fc_src */
61 struct connection *conn = objt_conn(smp->sess->origin);
62
63 if (conn && conn_get_src(conn))
64 src = conn_src(conn);
65 }
66 else /* src */
Willy Tarreaud68ff012022-05-27 08:57:21 +020067 src = (smp->strm ? sc_src(smp->strm->scf) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +020068
Christopher Fauletc03be1a2021-10-25 08:01:20 +020069 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +020070 return 0;
71
Christopher Fauletc03be1a2021-10-25 08:01:20 +020072 switch (src->ss_family) {
Willy Tarreau8987e7a2020-08-28 11:37:21 +020073 case AF_INET:
Christopher Fauletc03be1a2021-10-25 08:01:20 +020074 smp->data.u.ipv4 = ((struct sockaddr_in *)src)->sin_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +020075 smp->data.type = SMP_T_IPV4;
76 break;
77 case AF_INET6:
Christopher Fauletc03be1a2021-10-25 08:01:20 +020078 smp->data.u.ipv6 = ((struct sockaddr_in6 *)src)->sin6_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +020079 smp->data.type = SMP_T_IPV6;
80 break;
81 default:
82 return 0;
83 }
84
85 smp->flags = 0;
86 return 1;
87}
88
Christopher Faulet7d081f02021-04-15 09:38:37 +020089/* set temp integer to the connection's source port. Depending on the
90 * keyword, it may be the frontend or the backend connection.
91 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +020092static int
Christopher Faulet7d081f02021-04-15 09:38:37 +020093smp_fetch_sport(const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8987e7a2020-08-28 11:37:21 +020094{
Christopher Fauletc03be1a2021-10-25 08:01:20 +020095 const struct sockaddr_storage *src = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +020096
Christopher Faulet888cd702021-10-25 16:58:50 +020097 if (kw[0] == 'b') { /* bc_src_port */
Christopher Fauletc03be1a2021-10-25 08:01:20 +020098 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +020099 ? sc_conn(__objt_check(smp->sess->origin)->sc)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200100 : (smp->strm ? sc_conn(smp->strm->scb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200101 if (conn && conn_get_src(conn))
102 src = conn_src(conn);
103 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200104 else if (kw[0] == 'f') { /* fc_src_port */
105 struct connection *conn = objt_conn(smp->sess->origin);
106
107 if (conn && conn_get_src(conn))
108 src = conn_src(conn);
109 }
110 else /* src_port */
Willy Tarreaud68ff012022-05-27 08:57:21 +0200111 src = (smp->strm ? sc_src(smp->strm->scf) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200112
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200113 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200114 return 0;
115
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200116 smp->data.type = SMP_T_SINT;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200117 if (!(smp->data.u.sint = get_host_port(src)))
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200118 return 0;
119
120 smp->flags = 0;
121 return 1;
122}
123
Christopher Faulet7d081f02021-04-15 09:38:37 +0200124/* fetch the connection's destination IPv4/IPv6 address. Depending on the
125 * keyword, it may be the frontend or the backend connection.
126 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200127static int
128smp_fetch_dst(const struct arg *args, struct sample *smp, const char *kw, void *private)
129{
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200130 const struct sockaddr_storage *dst = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +0200131
Christopher Faulet888cd702021-10-25 16:58:50 +0200132 if (kw[0] == 'b') { /* bc_dst */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200133 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +0200134 ? sc_conn(__objt_check(smp->sess->origin)->sc)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200135 : (smp->strm ? sc_conn(smp->strm->scb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200136 if (conn && conn_get_dst(conn))
137 dst = conn_dst(conn);
138 }
Christopher Faulet888cd702021-10-25 16:58:50 +0200139 else if (kw[0] == 'f') { /* fc_dst */
140 struct connection *conn = objt_conn(smp->sess->origin);
141
142 if (conn && conn_get_dst(conn))
143 dst = conn_dst(conn);
144 }
145 else /* dst */
Willy Tarreaud68ff012022-05-27 08:57:21 +0200146 dst = (smp->strm ? sc_dst(smp->strm->scf) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200147
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200148 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200149 return 0;
150
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200151 switch (dst->ss_family) {
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200152 case AF_INET:
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200153 smp->data.u.ipv4 = ((struct sockaddr_in *)dst)->sin_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200154 smp->data.type = SMP_T_IPV4;
155 break;
156 case AF_INET6:
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200157 smp->data.u.ipv6 = ((struct sockaddr_in6 *)dst)->sin6_addr;
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200158 smp->data.type = SMP_T_IPV6;
159 break;
160 default:
161 return 0;
162 }
163
164 smp->flags = 0;
165 return 1;
166}
167
168/* check if the destination address of the front connection is local to the
169 * system or if it was intercepted.
170 */
171int smp_fetch_dst_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
172{
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200173 struct listener *li = smp->sess->listener;
Christopher Faulet888cd702021-10-25 16:58:50 +0200174 const struct sockaddr_storage *dst = NULL;
175
176 if (kw[0] == 'f') { /* fc_dst_is_local */
177 struct connection *conn = objt_conn(smp->sess->origin);
178
Aurelien DARRAGON819817f2023-03-10 16:53:43 +0100179 if (conn && conn_get_dst(conn))
Christopher Faulet888cd702021-10-25 16:58:50 +0200180 dst = conn_dst(conn);
181 }
182 else /* dst_is_local */
Willy Tarreaud68ff012022-05-27 08:57:21 +0200183 dst = (smp->strm ? sc_dst(smp->strm->scf) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200184
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200185 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200186 return 0;
187
188 smp->data.type = SMP_T_BOOL;
189 smp->flags = 0;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200190 smp->data.u.sint = addr_is_local(li->rx.settings->netns, dst);
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200191 return smp->data.u.sint >= 0;
192}
193
194/* check if the source address of the front connection is local to the system
195 * or not.
196 */
197int smp_fetch_src_is_local(const struct arg *args, struct sample *smp, const char *kw, void *private)
198{
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200199 struct listener *li = smp->sess->listener;
Christopher Faulet888cd702021-10-25 16:58:50 +0200200 const struct sockaddr_storage *src = NULL;
201
202 if (kw[0] == 'f') { /* fc_src_is_local */
203 struct connection *conn = objt_conn(smp->sess->origin);
204
205 if (conn && conn_get_src(conn))
206 src = conn_src(conn);
207 }
208 else /* src_is_local */
Willy Tarreaud68ff012022-05-27 08:57:21 +0200209 src = (smp->strm ? sc_src(smp->strm->scf) : sess_src(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200210
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200211 if (!src)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200212 return 0;
213
214 smp->data.type = SMP_T_BOOL;
215 smp->flags = 0;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200216 smp->data.u.sint = addr_is_local(li->rx.settings->netns, src);
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200217 return smp->data.u.sint >= 0;
218}
219
Christopher Faulet7d081f02021-04-15 09:38:37 +0200220/* set temp integer to the connexion's destination port. Depending on the
221 * keyword, it may be the frontend or the backend connection.
222 */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200223static int
224smp_fetch_dport(const struct arg *args, struct sample *smp, const char *kw, void *private)
225{
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200226 const struct sockaddr_storage *dst = NULL;
Christopher Faulet003df1c2021-04-15 09:39:38 +0200227
Christopher Faulet888cd702021-10-25 16:58:50 +0200228 if (kw[0] == 'b') { /* bc_dst_port */
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200229 struct connection *conn = ((obj_type(smp->sess->origin) == OBJ_TYPE_CHECK)
Willy Tarreaubde14ad2022-05-27 10:04:04 +0200230 ? sc_conn(__objt_check(smp->sess->origin)->sc)
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200231 : (smp->strm ? sc_conn(smp->strm->scb): NULL));
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200232 if (conn && conn_get_dst(conn))
233 dst = conn_dst(conn);
234 }
Aurelien DARRAGON819817f2023-03-10 16:53:43 +0100235 else if (kw[0] == 'f') { /* fc_dst_port */
Christopher Faulet888cd702021-10-25 16:58:50 +0200236 struct connection *conn = objt_conn(smp->sess->origin);
237
Aurelien DARRAGON819817f2023-03-10 16:53:43 +0100238 if (conn && conn_get_dst(conn))
Christopher Faulet888cd702021-10-25 16:58:50 +0200239 dst = conn_dst(conn);
240 }
241 else /* dst_port */
Willy Tarreaud68ff012022-05-27 08:57:21 +0200242 dst = (smp->strm ? sc_dst(smp->strm->scf) : sess_dst(smp->sess));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200243
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200244 if (!dst)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200245 return 0;
246
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200247 smp->data.type = SMP_T_SINT;
Christopher Fauletc03be1a2021-10-25 08:01:20 +0200248 if (!(smp->data.u.sint = get_host_port(dst)))
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200249 return 0;
250
251 smp->flags = 0;
252 return 1;
253}
254
255#ifdef TCP_INFO
256
257
258/* Validates the arguments passed to "fc_*" fetch keywords returning a time
259 * value. These keywords support an optional string representing the unit of the
260 * result: "us" for microseconds and "ms" for milliseconds". Returns 0 on error
261 * and non-zero if OK.
262 */
263static int val_fc_time_value(struct arg *args, char **err)
264{
265 if (args[0].type == ARGT_STR) {
266 if (strcmp(args[0].data.str.area, "us") == 0) {
267 chunk_destroy(&args[0].data.str);
268 args[0].type = ARGT_SINT;
269 args[0].data.sint = TIME_UNIT_US;
270 }
271 else if (strcmp(args[0].data.str.area, "ms") == 0) {
272 chunk_destroy(&args[0].data.str);
273 args[0].type = ARGT_SINT;
274 args[0].data.sint = TIME_UNIT_MS;
275 }
276 else {
277 memprintf(err, "expects 'us' or 'ms', got '%s'",
278 args[0].data.str.area);
279 return 0;
280 }
281 }
282 else {
283 memprintf(err, "Unexpected arg type");
284 return 0;
285 }
286
287 return 1;
288}
289
290/* Validates the arguments passed to "fc_*" fetch keywords returning a
291 * counter. These keywords should be used without any keyword, but because of a
292 * bug in previous versions, an optional string argument may be passed. In such
293 * case, the argument is ignored and a warning is emitted. Returns 0 on error
294 * and non-zero if OK.
295 */
296static int var_fc_counter(struct arg *args, char **err)
297{
298 if (args[0].type != ARGT_STOP) {
299 ha_warning("no argument supported for 'fc_*' sample expressions returning counters.\n");
300 if (args[0].type == ARGT_STR)
301 chunk_destroy(&args[0].data.str);
302 args[0].type = ARGT_STOP;
303 }
304
305 return 1;
306}
307
308/* Returns some tcp_info data if it's available. "dir" must be set to 0 if
309 * the client connection is required, otherwise it is set to 1. "val" represents
310 * the required value.
311 * If the function fails it returns 0, otherwise it returns 1 and "result" is filled.
312 */
313static inline int get_tcp_info(const struct arg *args, struct sample *smp,
314 int dir, int val)
315{
316 struct connection *conn;
317 struct tcp_info info;
318 socklen_t optlen;
319
320 /* strm can be null. */
321 if (!smp->strm)
322 return 0;
323
Willy Tarreau4596fe22022-05-17 19:07:51 +0200324 /* get the object associated with the stream connector.The
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200325 * object can be other thing than a connection. For example,
Willy Tarreau4596fe22022-05-17 19:07:51 +0200326 * it be a appctx.
327 */
Willy Tarreaufd9417b2022-05-18 16:23:22 +0200328 conn = (dir == 0 ? sc_conn(smp->strm->scf) : sc_conn(smp->strm->scb));
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200329 if (!conn)
330 return 0;
331
332 /* The fd may not be available for the tcp_info struct, and the
333 syscal can fail. */
334 optlen = sizeof(info);
Willy Tarreaue2226792022-04-11 18:04:33 +0200335 if ((conn->flags & CO_FL_FDLESS) ||
336 getsockopt(conn->handle.fd, IPPROTO_TCP, TCP_INFO, &info, &optlen) == -1)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200337 return 0;
338
339 /* extract the value. */
340 smp->data.type = SMP_T_SINT;
341 switch (val) {
David CARLIER7747d462022-04-11 12:53:11 +0100342#if defined(__APPLE__)
343 case 0: smp->data.u.sint = info.tcpi_rttcur; break;
344 case 1: smp->data.u.sint = info.tcpi_rttvar; break;
345 case 2: smp->data.u.sint = info.tcpi_tfo_syn_data_acked; break;
346 case 4: smp->data.u.sint = info.tcpi_tfo_syn_loss; break;
347 case 5: smp->data.u.sint = info.tcpi_rto; break;
348#else
349 /* all other platforms supporting TCP_INFO have these ones */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200350 case 0: smp->data.u.sint = info.tcpi_rtt; break;
351 case 1: smp->data.u.sint = info.tcpi_rttvar; break;
David CARLIER7747d462022-04-11 12:53:11 +0100352# if defined(__linux__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200353 /* these ones are common to all Linux versions */
354 case 2: smp->data.u.sint = info.tcpi_unacked; break;
355 case 3: smp->data.u.sint = info.tcpi_sacked; break;
356 case 4: smp->data.u.sint = info.tcpi_lost; break;
357 case 5: smp->data.u.sint = info.tcpi_retrans; break;
358 case 6: smp->data.u.sint = info.tcpi_fackets; break;
359 case 7: smp->data.u.sint = info.tcpi_reordering; break;
Brad Smith02fd3ca2022-08-12 22:23:13 -0400360# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
361 /* the ones are found on FreeBSD, NetBSD and OpenBSD featuring TCP_INFO */
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200362 case 2: smp->data.u.sint = info.__tcpi_unacked; break;
363 case 3: smp->data.u.sint = info.__tcpi_sacked; break;
364 case 4: smp->data.u.sint = info.__tcpi_lost; break;
365 case 5: smp->data.u.sint = info.__tcpi_retrans; break;
366 case 6: smp->data.u.sint = info.__tcpi_fackets; break;
367 case 7: smp->data.u.sint = info.__tcpi_reordering; break;
David CARLIER7747d462022-04-11 12:53:11 +0100368# endif
369#endif // apple
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200370 default: return 0;
371 }
372
373 return 1;
374}
375
376/* get the mean rtt of a client connection */
377static int
378smp_fetch_fc_rtt(const struct arg *args, struct sample *smp, const char *kw, void *private)
379{
380 if (!get_tcp_info(args, smp, 0, 0))
381 return 0;
382
383 /* By default or if explicitly specified, convert rtt to ms */
384 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
385 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
386
387 return 1;
388}
389
390/* get the variance of the mean rtt of a client connection */
391static int
392smp_fetch_fc_rttvar(const struct arg *args, struct sample *smp, const char *kw, void *private)
393{
394 if (!get_tcp_info(args, smp, 0, 1))
395 return 0;
396
397 /* By default or if explicitly specified, convert rttvar to ms */
398 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
399 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
400
401 return 1;
402}
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200403
Aleksandar Lazic5529c992023-04-28 11:39:12 +0200404/* get the mean rtt of a backend connection */
405static int
406smp_fetch_bc_rtt(const struct arg *args, struct sample *smp, const char *kw, void *private)
407{
408 if (!get_tcp_info(args, smp, 1, 0))
409 return 0;
410
411 /* By default or if explicitly specified, convert rtt to ms */
412 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
413 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
414
415 return 1;
416}
417
418/* get the variance of the mean rtt of a backend connection */
419static int
420smp_fetch_bc_rttvar(const struct arg *args, struct sample *smp, const char *kw, void *private)
421{
422 if (!get_tcp_info(args, smp, 1, 1))
423 return 0;
424
425 /* By default or if explicitly specified, convert rttvar to ms */
426 if (!args || args[0].type == ARGT_STOP || args[0].data.sint == TIME_UNIT_MS)
427 smp->data.u.sint = (smp->data.u.sint + 500) / 1000;
428
429 return 1;
430}
431
432
Brad Smith02fd3ca2022-08-12 22:23:13 -0400433#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200434/* get the unacked counter on a client connection */
435static int
436smp_fetch_fc_unacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
437{
438 if (!get_tcp_info(args, smp, 0, 2))
439 return 0;
440 return 1;
441}
David CARLIER5c83e3a2022-04-11 12:41:24 +0100442#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200443
Brad Smith02fd3ca2022-08-12 22:23:13 -0400444#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200445/* get the sacked counter on a client connection */
446static int
447smp_fetch_fc_sacked(const struct arg *args, struct sample *smp, const char *kw, void *private)
448{
449 if (!get_tcp_info(args, smp, 0, 3))
450 return 0;
451 return 1;
452}
David CARLIER5c83e3a2022-04-11 12:41:24 +0100453#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200454
Brad Smith02fd3ca2022-08-12 22:23:13 -0400455#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200456/* get the lost counter on a client connection */
457static int
458smp_fetch_fc_lost(const struct arg *args, struct sample *smp, const char *kw, void *private)
459{
460 if (!get_tcp_info(args, smp, 0, 4))
461 return 0;
462 return 1;
463}
David CARLIER5c83e3a2022-04-11 12:41:24 +0100464#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200465
Brad Smith02fd3ca2022-08-12 22:23:13 -0400466#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200467/* get the retrans counter on a client connection */
468static int
469smp_fetch_fc_retrans(const struct arg *args, struct sample *smp, const char *kw, void *private)
470{
471 if (!get_tcp_info(args, smp, 0, 5))
472 return 0;
473 return 1;
474}
David CARLIER5c83e3a2022-04-11 12:41:24 +0100475#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200476
Brad Smith02fd3ca2022-08-12 22:23:13 -0400477#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200478/* get the fackets counter on a client connection */
479static int
480smp_fetch_fc_fackets(const struct arg *args, struct sample *smp, const char *kw, void *private)
481{
482 if (!get_tcp_info(args, smp, 0, 6))
483 return 0;
484 return 1;
485}
David CARLIER5c83e3a2022-04-11 12:41:24 +0100486#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200487
Brad Smith02fd3ca2022-08-12 22:23:13 -0400488#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200489/* get the reordering counter on a client connection */
490static int
491smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *kw, void *private)
492{
493 if (!get_tcp_info(args, smp, 0, 7))
494 return 0;
495 return 1;
496}
David CARLIER5c83e3a2022-04-11 12:41:24 +0100497#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200498#endif // TCP_INFO
499
500/* Note: must not be declared <const> as its list will be overwritten.
501 * Note: fetches that may return multiple types must be declared as the lowest
502 * common denominator, the type that can be casted into all other ones. For
503 * instance v4/v6 must be declared v4.
504 */
505static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Aurelien DARRAGON35d5b5f2023-06-07 15:12:06 +0200506 { "bc_dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4SRV },
Christopher Faulet7d081f02021-04-15 09:38:37 +0200507 { "bc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
Aurelien DARRAGON35d5b5f2023-06-07 15:12:06 +0200508 { "bc_src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4SRV },
Christopher Faulet7d081f02021-04-15 09:38:37 +0200509 { "bc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4SRV },
510
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200511 { "dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
512 { "dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
513 { "dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
Christopher Faulet888cd702021-10-25 16:58:50 +0200514
515 { "fc_dst", smp_fetch_dst, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
516 { "fc_dst_is_local", smp_fetch_dst_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
517 { "fc_dst_port", smp_fetch_dport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
518
519 { "fc_src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
520 { "fc_src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
521 { "fc_src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
522
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200523 { "src", smp_fetch_src, 0, NULL, SMP_T_IPV4, SMP_USE_L4CLI },
524 { "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
525 { "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
526#ifdef TCP_INFO
527 { "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
528 { "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
Aleksandar Lazic5529c992023-04-28 11:39:12 +0200529 { "bc_rtt", smp_fetch_bc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
530 { "bc_rttvar", smp_fetch_bc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
531
Brad Smith02fd3ca2022-08-12 22:23:13 -0400532#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200533 { "fc_unacked", smp_fetch_fc_unacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
David CARLIER5c83e3a2022-04-11 12:41:24 +0100534#endif
Brad Smith02fd3ca2022-08-12 22:23:13 -0400535#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200536 { "fc_sacked", smp_fetch_fc_sacked, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
David CARLIER5c83e3a2022-04-11 12:41:24 +0100537#endif
Brad Smith02fd3ca2022-08-12 22:23:13 -0400538#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200539 { "fc_retrans", smp_fetch_fc_retrans, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
David CARLIER5c83e3a2022-04-11 12:41:24 +0100540#endif
Brad Smith02fd3ca2022-08-12 22:23:13 -0400541#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200542 { "fc_fackets", smp_fetch_fc_fackets, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
David CARLIER5c83e3a2022-04-11 12:41:24 +0100543#endif
Brad Smith02fd3ca2022-08-12 22:23:13 -0400544#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200545 { "fc_lost", smp_fetch_fc_lost, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
David CARLIER5c83e3a2022-04-11 12:41:24 +0100546#endif
Brad Smith02fd3ca2022-08-12 22:23:13 -0400547#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200548 { "fc_reordering", smp_fetch_fc_reordering, ARG1(0,STR), var_fc_counter, SMP_T_SINT, SMP_USE_L4CLI },
David CARLIER5c83e3a2022-04-11 12:41:24 +0100549#endif
Willy Tarreau8987e7a2020-08-28 11:37:21 +0200550#endif // TCP_INFO
551 { /* END */ },
552}};
553
554INITCALL1(STG_REGISTER, sample_register_fetches, &sample_fetch_keywords);
555
556
557/*
558 * Local variables:
559 * c-indent-level: 8
560 * c-basic-offset: 8
561 * End:
562 */