mirror of
http://git.haproxy.org/git/haproxy.git
synced 2026-02-10 11:12:46 +02:00
MINOR: net_helper: extend the ip.fp output with an option presence mask
Emeric suggested that it's sometimes convenient to instantly know if a client has advertised support for window scaling or timestamps for example. While the info is present in the TCP options output, it's hard to extract since it respects the options order. So here we're extending the 56-bit fingerprint with 8 extra bits that indicate the presence of options 2..8, and any option above 9 for the last bit. In practice this is sufficient since higher options are not commonly used. Also TCP option 5 is normally not sent on the SYN (SACK, only SACK_perm is sent), and echo options 6 & 7 are no longer used (replaced with timestamps). These fields might be repurposed in the future if some more meaningful options are to be mapped (e.g. MPTCP, TFO cookie, auth).
This commit is contained in:
@@ -21239,9 +21239,9 @@ ip.fp([<mode>])
|
||||
can be used to distinguish between multiple apparently identical hosts. The
|
||||
real-world use case is to refine the identification of misbehaving hosts
|
||||
between a shared IP address to avoid blocking legitimate users when only one
|
||||
is misbehaving and needs to be blocked. The converter builds a 7-byte binary
|
||||
block based on the input. The bytes of the fingerprint are arranged like
|
||||
this:
|
||||
is misbehaving and needs to be blocked. The converter builds a 8-byte minimum
|
||||
binary block based on the input. The bytes of the fingerprint are arranged
|
||||
like this:
|
||||
- byte 0: IP TOS field (see ip.tos)
|
||||
- byte 1:
|
||||
- bit 7: IPv6 (1) / IPv4 (0)
|
||||
@@ -21256,10 +21256,13 @@ ip.fp([<mode>])
|
||||
- bits 3..0: TCP window scaling + 1 (1..15) / 0 (no WS advertised)
|
||||
- byte 3..4: tcp.win
|
||||
- byte 5..6: tcp.options.mss, or zero if absent
|
||||
- byte 7: 1 bit per present TCP option, with options 2 to 8 being mapped to
|
||||
bits 0..6 respectively, and bit 7 indicating the presence of any
|
||||
option from 9 to 255.
|
||||
|
||||
The <mode> argument permits to append more information to the fingerprint. By
|
||||
default, when the <mode> argument is not set or is zero, the fingerprint is
|
||||
solely made of the 7 bytes described above. If <mode> is specified as another
|
||||
solely made of the 8 bytes described above. If <mode> is specified as another
|
||||
value, it then corresponds to the sum of the following values, and the
|
||||
respective components will be concatenated to the fingerprint, in the order
|
||||
below:
|
||||
@@ -21269,7 +21272,7 @@ ip.fp([<mode>])
|
||||
- 4: the source IP address is appended to the fingerprint, which adds
|
||||
4 bytes for IPv4 and 16 for IPv6.
|
||||
|
||||
Example: make a 12..24 bytes fingerprint using the base FP, the TTL and the
|
||||
Example: make a 13..25 bytes fingerprint using the base FP, the TTL and the
|
||||
source address (1+4=5):
|
||||
|
||||
frontend test
|
||||
|
||||
@@ -652,8 +652,8 @@ static int sample_conv_tcp_win(const struct arg *arg_p, struct sample *smp, void
|
||||
/* Builds a binary fingerprint of the IP+TCP input contents that are supposed
|
||||
* to rely essentially on the client stack's settings. This can be used for
|
||||
* example to selectively block bad behaviors at one IP address without
|
||||
* blocking others. The resulting fingerprint is a binary block of 56 to 376
|
||||
* bytes long (56 being the fixed part and the rest depending on the provided
|
||||
* blocking others. The resulting fingerprint is a binary block of 64 to 384
|
||||
* bits long (64 being the fixed part and the rest depending on the provided
|
||||
* TCP extensions).
|
||||
*/
|
||||
static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
@@ -668,6 +668,7 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
||||
uchar tcpflags;
|
||||
uchar tcplen;
|
||||
uchar tcpws;
|
||||
uchar opts;
|
||||
ushort pktlen;
|
||||
ushort tcpwin;
|
||||
ushort tcpmss;
|
||||
@@ -719,8 +720,8 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
||||
else
|
||||
return 0;
|
||||
|
||||
/* prepare trash to contain at least 7 bytes */
|
||||
trash->data = 7;
|
||||
/* prepare trash to contain at least 8 bytes */
|
||||
trash->data = 8;
|
||||
|
||||
/* store the TOS in the FP's first byte */
|
||||
trash->area[0] = iptos;
|
||||
@@ -763,9 +764,11 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
||||
(tcpflags >> 6 << 0); // CWR, ECE
|
||||
|
||||
tcpmss = tcpws = 0;
|
||||
opts = 0;
|
||||
ofs = 20;
|
||||
while (ofs < tcplen) {
|
||||
size_t next;
|
||||
uchar opt;
|
||||
|
||||
if (smp->data.u.str.area[ofs] == 0) // kind0=end of options
|
||||
break;
|
||||
@@ -782,17 +785,24 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
||||
break;
|
||||
|
||||
/* option is complete, take a copy of it */
|
||||
if (mode & 2) // mode & 2: append tcp.options_list
|
||||
trash->area[trash->data++] = smp->data.u.str.area[ofs];
|
||||
opt = smp->data.u.str.area[ofs];
|
||||
|
||||
if (smp->data.u.str.area[ofs] == 2 /* MSS */) {
|
||||
if (mode & 2) // mode & 2: append tcp.options_list
|
||||
trash->area[trash->data++] = opt;
|
||||
|
||||
if (opt == 2 /* MSS */) {
|
||||
tcpmss = read_n16(smp->data.u.str.area + ofs + 2);
|
||||
}
|
||||
else if (smp->data.u.str.area[ofs] == 3 /* WS */) {
|
||||
else if (opt == 3 /* WS */) {
|
||||
tcpws = (uchar)smp->data.u.str.area[ofs + 2];
|
||||
/* output from 1 to 15, thus 0=not found */
|
||||
tcpws = tcpws > 14 ? 15 : tcpws + 1;
|
||||
}
|
||||
|
||||
/* keep a presence mask of opts 2..8 and others */
|
||||
if (opt >= 2)
|
||||
opts |= 1 << (opt < 9 ? opt - 2 : 7);
|
||||
|
||||
ofs = next;
|
||||
}
|
||||
|
||||
@@ -803,6 +813,9 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
||||
write_n16(trash->area + 3, tcpwin);
|
||||
write_n16(trash->area + 5, tcpmss);
|
||||
|
||||
/* the the bit mask of present options */
|
||||
trash->area[7] = opts;
|
||||
|
||||
/* mode 4: append source IP address */
|
||||
if (mode & 4) {
|
||||
iplen = (ipver == 4) ? 4 : 16;
|
||||
|
||||
Reference in New Issue
Block a user