MEDIUM: sample: Add IPv6 support to the ipmask converter

Add an optional second parameter to the ipmask converter that specifies
the number of bits to mask off IPv6 addresses.

If the second parameter is not given IPv6 addresses fail to mask (resulting
in an empty string), preserving backwards compatibility: Previously
a sample like `src,ipmask(24)` failed to give a result for IPv6 addresses.

This feature can be tested like this:

  defaults
  	log	global
  	mode	http
  	option	httplog
  	option	dontlognull
  	timeout connect 5000
  	timeout client  50000
  	timeout server  50000

  frontend fe
  	bind :::8080 v4v6

  	# Masked IPv4 for IPv4, empty for IPv6 (with and without this commit)
  	http-response set-header Test %[src,ipmask(24)]
  	# Correctly masked IP addresses for both IPv4 and IPv6
  	http-response set-header Test2 %[src,ipmask(24,ffff:ffff:ffff:ffff::)]
  	# Correctly masked IP addresses for both IPv4 and IPv6
  	http-response set-header Test3 %[src,ipmask(24,64)]

  	default_backend be

  backend be
  	server s example.com:80

Tested-By: Jarno Huuskonen <jarno.huuskonen@uef.fi>
This commit is contained in:
Tim Duesterhus 2018-01-25 16:24:51 +01:00 committed by Willy Tarreau
parent b814da6c5c
commit 1478aa795e
2 changed files with 29 additions and 9 deletions

View File

@ -12870,11 +12870,14 @@ in_table(<table>)
the presence of a certain key in a table tracking some elements (e.g. whether
or not a source IP address or an Authorization header was already seen).
ipmask(<mask>)
Apply a mask to an IPv4 address, and use the result for lookups and storage.
ipmask(<mask4>, [<mask6>])
Apply a mask to an IP address, and use the result for lookups and storage.
This can be used to make all hosts within a certain mask to share the same
table entries and as such use the same server. The mask can be passed in
dotted form (e.g. 255.255.255.0) or in CIDR form (e.g. 24).
table entries and as such use the same server. The mask4 can be passed in
dotted form (e.g. 255.255.255.0) or in CIDR form (e.g. 24). The mask6 can
be passed in quadruplet form (e.g. ffff:ffff::) or in CIDR form (e.g. 64).
If no mask6 is given IPv6 addresses will fail to convert for backwards
compatibility reasons.
json([<input-code>])
Escapes the input string and produces an ASCII output string ready to use as a

View File

@ -1603,11 +1603,28 @@ static int sample_conv_str2upper(const struct arg *arg_p, struct sample *smp, vo
return 1;
}
/* takes the netmask in arg_p */
static int sample_conv_ipmask(const struct arg *arg_p, struct sample *smp, void *private)
/* takes the IPv4 mask in args[0] and an optional IPv6 mask in args[1] */
static int sample_conv_ipmask(const struct arg *args, struct sample *smp, void *private)
{
smp->data.u.ipv4.s_addr &= arg_p->data.ipv4.s_addr;
smp->data.type = SMP_T_IPV4;
/* Attempt to convert to IPv4 to apply the correct mask. */
c_ipv62ip(smp);
if (smp->data.type == SMP_T_IPV4) {
smp->data.u.ipv4.s_addr &= args[0].data.ipv4.s_addr;
smp->data.type = SMP_T_IPV4;
}
else if (smp->data.type == SMP_T_IPV6) {
/* IPv6 cannot be converted without an IPv6 mask. */
if (args[1].type != ARGT_IPV6)
return 0;
*(uint32_t*)&smp->data.u.ipv6.s6_addr[0] &= *(uint32_t*)&args[1].data.ipv6.s6_addr[0];
*(uint32_t*)&smp->data.u.ipv6.s6_addr[4] &= *(uint32_t*)&args[1].data.ipv6.s6_addr[4];
*(uint32_t*)&smp->data.u.ipv6.s6_addr[8] &= *(uint32_t*)&args[1].data.ipv6.s6_addr[8];
*(uint32_t*)&smp->data.u.ipv6.s6_addr[12] &= *(uint32_t*)&args[1].data.ipv6.s6_addr[12];
smp->data.type = SMP_T_IPV6;
}
return 1;
}
@ -2809,7 +2826,7 @@ static struct sample_conv_kw_list sample_conv_kws = {ILH, {
{ "length", sample_conv_length, 0, NULL, SMP_T_STR, SMP_T_SINT },
{ "hex", sample_conv_bin2hex, 0, NULL, SMP_T_BIN, SMP_T_STR },
{ "hex2i", sample_conv_hex2int, 0, NULL, SMP_T_STR, SMP_T_SINT },
{ "ipmask", sample_conv_ipmask, ARG1(1,MSK4), NULL, SMP_T_IPV4, SMP_T_IPV4 },
{ "ipmask", sample_conv_ipmask, ARG2(1,MSK4,MSK6), NULL, SMP_T_ADDR, SMP_T_IPV4 },
{ "ltime", sample_conv_ltime, ARG2(1,STR,SINT), NULL, SMP_T_SINT, SMP_T_STR },
{ "utime", sample_conv_utime, ARG2(1,STR,SINT), NULL, SMP_T_SINT, SMP_T_STR },
{ "crc32", sample_conv_crc32, ARG1(0,SINT), NULL, SMP_T_BIN, SMP_T_SINT },