Skip to content

Commit 6fb521d

Browse files
committed
MINOR: tcp_sample: implement the fc_saved_syn sample fetch function
This function retrieves the copy of a SYN packet that the system has kept for us when bind option "tcp-ss" was set to 1 or above. It's recommended to copy it to a local variable because it will be freed after being read. It allows to inspect all parts of an incoming SYN packet, provided that it was preserved (e.g. not possible with SYN cookies). The doc provides examples of how to use it.
1 parent 52d60bf commit 6fb521d

File tree

2 files changed

+104
-2
lines changed

2 files changed

+104
-2
lines changed

doc/configuration.txt

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17516,13 +17516,14 @@ tcp-ss <mode>
1751617516
Sets the TCP Save SYN option for all incoming connections instantiated from
1751717517
this listening socket. This option is available on Linux since version 4.3.
1751817518
It instructs the kernel to try to keep a copy of the incoming IP packet
17519-
containing the TCP SYN flag, for later inspection. The option knows 3 modes:
17519+
containing the TCP SYN flag, for later inspection via the "fc_saved_syn"
17520+
sample fetch function. The option knows 3 modes:
1752017521
- 0 SYN packet saving is disabled, this is the default
1752117522
- 1 SYN packet saving is enabled, and contains IP and TCP headers
1752217523
- 2 SYN packet saving is enabled, and contains ETH, IP and TCP headers
1752317524

1752417525
This only works for regular TCP connections, and is ignored for other
17525-
protocols (e.g. UNIX sockets). See also "fc.saved_syn".
17526+
protocols (e.g. UNIX sockets). See also "fc_saved_syn".
1752617527

1752717528
tcp-ut <delay>
1752817529
Sets the TCP User Timeout for all incoming connections instantiated from this
@@ -23277,6 +23278,7 @@ fc_retrans integer
2327723278
fc_rtt(<unit>) integer
2327823279
fc_rttvar(<unit>) integer
2327923280
fc_sacked integer
23281+
fc_saved_syn binary
2328023282
fc_settings_streams_limit integer
2328123283
fc_src ip
2328223284
fc_src_is_local boolean
@@ -23875,6 +23877,78 @@ fc_sacked : integer
2387523877
if the operating system does not support TCP_INFO, for example Linux kernels
2387623878
before 2.4, the sample fetch fails.
2387723879

23880+
fc_saved_syn : binary
23881+
Returns a copy of the saved SYN packet that was preserved by the system
23882+
during the incoming connection setup. This requires that the "tcp-ss" option
23883+
was present on the "bind" line, and a Linux kernel 4.3 minimum. When "tcp-ss"
23884+
is set to 1, only the IP and TCP headers are present. When "tcp-ss" is set to
23885+
2, then the Ethernet header is also present before the IP header, and may be
23886+
used to control or log source MAC address or VLANs for example. Note that
23887+
there is no guarantee that a SYN will be saved. For example, if SYN cookies
23888+
are used, the SYN packet is not preserved and the connection is established
23889+
on the matching ACK packet. In addition, the system doesn't guarantee to
23890+
preserve the copy beyond the first read. As such it is strongly recommended
23891+
to copy it into a variable in scope "sess" from a "tcp-request connection"
23892+
rule and only use that variable for further manipulations. It is worth noting
23893+
that on the loopback interface a dummy 14-byte ethernet header is constructed
23894+
by the system where both the source and destination addresses are zero, and
23895+
only the protocol is set. It is convenient to convert such samples to
23896+
hexadecimal using the "hex" converter during debugging. Example (fields
23897+
manually separated and commented below):
23898+
23899+
frontend test
23900+
mode http
23901+
bind :::4445 tcp-ss 2
23902+
tcp-request connection set-var(sess.syn) fc_saved_syn
23903+
http-request return status 200 content-type text/plain \
23904+
lf-string "%[var(sess.syn),hex]\n"
23905+
23906+
$ curl '0:4445'
23907+
000000000000 000000000000 0800 \ # MAC_DST MAC_SRC PROTO=IPv4
23908+
4500003C0A65400040063255 \ # IPv4 header, proto=6 (TCP)
23909+
7F000001 7F000001 \ # IP_SRC=127.0.0.1 IP_DST=127.0.0.1
23910+
E1F2 115D 01AF4E3E 00000000 \ # TCP_SPORT=57842 TCP_DPORT=4445, SEQ
23911+
A0 02 FFD7 FE300000 \ # OPT_LEN=20 TCP_FLAGS=SYN WIN=65495
23912+
0204FFD70402080A01C2A71A0000000001030307 # MSS=65495, TS, SACK, WSCALE 7
23913+
23914+
$ curl '[::1]:4445'
23915+
000000000000 000000000000 86DD \ # MAC_DST MAC_SRC PROTO=IPv6
23916+
6008018F00280640 \ # IPv6 header, proto=6 (TCP)
23917+
00000000000000000000000000000001 \ # SRC=::1
23918+
00000000000000000000000000000001 \ # DST=::1
23919+
9758 115D B5511F5D 00000000 \ # TCP_SPORT=38744 TCP_DPORT=4445, SEQ
23920+
A0 02 FFC4 00300000 \ # OPT_LEN=20 TCP_FLAGS=SYN WIN=65476
23921+
0204FFC40402080A9C231D680000000001030307 # MSS=65476, TS, SACK, WSCALE 7
23922+
23923+
The "bytes()" converter helps extract specific fields from the packet. The
23924+
be2dec() also permits to read chunks and emit them in integer form.
23925+
23926+
Example with IPv4 input:
23927+
23928+
frontend test
23929+
mode http
23930+
bind :4445 tcp-ss 2
23931+
tcp-request connection set-var(sess.syn) fc_saved_syn
23932+
http-request return status 200 content-type text/plain lf-string \
23933+
"mac_dst=%[var(sess.syn),bytes(0,6),hex] \
23934+
mac_src=%[var(sess.syn),bytes(6,6),hex] \
23935+
proto=%[var(sess.syn),bytes(12,2),hex] \
23936+
ipv4h=%[var(sess.syn),bytes(14,12),hex] \
23937+
ipv4_src=%[var(sess.syn),bytes(26,4),be2dec(.,1)] \
23938+
ipv4_dst=%[var(sess.syn),bytes(30,4),be2dec(.,1)] \
23939+
tcp_spt=%[var(sess.syn),bytes(34,2),be2dec(,2)] \
23940+
tcp_dpt=%[var(sess.syn),bytes(36,2),be2dec(,2)] \
23941+
tcp_win=%[var(sess.syn),bytes(48,2),be2dec(,2)] \
23942+
tcp_opt=%[var(sess.syn),bytes(54),hex]\n"
23943+
23944+
$ curl '0:4445'
23945+
mac_dst=000000000000 mac_src=000000000000 proto=0800 \
23946+
ipv4h=4500003CC9B7400040067302 ipv4_src=127.0.0.1 ipv4_dst=127.0.0.1 \
23947+
tcp_spt=43970 tcp_dpt=4445 tcp_win=65495 \
23948+
tcp_opt=0204FFD70402080A01DC0D410000000001030307
23949+
23950+
See also the "set-var" action, the "be2dec", "bytes" and "hex" converters.
23951+
2387823952
fc_settings_streams_limit : integer
2387923953
Returns the maximum number of streams allowed on the frontend connection. For
2388023954
TCP and HTTP/1.1 connections, it is always 1. For other protocols, it depends

src/tcp_sample.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,31 @@ smp_fetch_fc_reordering(const struct arg *args, struct sample *smp, const char *
465465
#endif
466466
#endif // TCP_INFO
467467

468+
#ifdef TCP_SAVED_SYN
469+
/* Try to retrieve the saved SYN packet header that has been enabled on a
470+
* TCP listener via the "tcp-ss" bind option.
471+
*/
472+
static int
473+
smp_fetch_fc_saved_syn(const struct arg *args, struct sample *smp, const char *kw, void *private)
474+
{
475+
struct connection *conn = objt_conn(smp->sess->origin);
476+
int ret;
477+
478+
if (!conn || !conn->ctrl->get_opt)
479+
return 0;
480+
481+
chunk_reset(&trash);
482+
ret = conn->ctrl->get_opt(conn, IPPROTO_TCP, TCP_SAVED_SYN, trash.area, trash.size);
483+
if (ret < 0)
484+
return 0;
485+
486+
trash.data = ret;
487+
smp->data.type = SMP_T_BIN;
488+
smp->data.u.str = trash;
489+
return 1;
490+
}
491+
#endif
492+
468493
/* Validates the data unit argument passed to "accept_date" fetch. Argument 0 support an
469494
* optional string representing the unit of the result: "s" for seconds, "ms" for
470495
* milliseconds and "us" for microseconds.
@@ -579,6 +604,9 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
579604
{ "src", smp_fetch_src, 0, NULL, SMP_T_ADDR, SMP_USE_L4CLI },
580605
{ "src_is_local", smp_fetch_src_is_local, 0, NULL, SMP_T_BOOL, SMP_USE_L4CLI },
581606
{ "src_port", smp_fetch_sport, 0, NULL, SMP_T_SINT, SMP_USE_L4CLI },
607+
#ifdef TCP_SAVED_SYN
608+
{ "fc_saved_syn", smp_fetch_fc_saved_syn, 0, NULL, SMP_T_BIN, SMP_USE_L4CLI },
609+
#endif
582610
#ifdef TCP_INFO
583611
{ "fc_rtt", smp_fetch_fc_rtt, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },
584612
{ "fc_rttvar", smp_fetch_fc_rttvar, ARG1(0,STR), val_fc_time_value, SMP_T_SINT, SMP_USE_L4CLI },

0 commit comments

Comments
 (0)