be2dec(separator,chunk_size[,truncate]) binary string
le2dec(separator,chunk_size[,truncate]) binary string
be2hex([separator[,chunk_size[,truncate]]]) binary string
+be_sort(elem_size) binary binary
bool integer boolean
bytes(offset[,length]) binary binary
capture-req(id) string string
bin(01020304050607),be2hex(--,2,1) # 0102--0304--0506
bin(0102030405060708),be2hex(,3,1) # 010203040506
+be_sort(<elem_size>)
+ Sorts in ascending numerical order the big-endian unsigned integers of
+ <elem_size> bytes stored in the binary input sample, and returns the
+ resulting binary sample. <elem_size> must be 1, 2, 4 or 8, and the length of
+ the input sample must be a multiple of <elem_size>, otherwise the conversion
+ fails. This is typically used to normalize a list of binary values whose
+ order may vary from one client to another before hashing it, such as the
+ cipher list or the extension list of a TLS client hello.
+
+ Example:
+ bin(0302000104),be_sort(1) # 0001020304
+ bin(1302130113031304),be_sort(2) # 1301130213031304
+ bin(010203),be_sort(2) # fails, not a multiple of 2
+
+ # hash of the client's cipher list, independent of the cipher order
+ http-request set-var(txn.ciphers) \
+ ssl_fc_cipherlist_bin(1),be_sort(2),xxh64
+
bool
Returns a boolean TRUE if the input value of type signed integer is
non-null, otherwise returns FALSE. Used in conjunction with and(), it can be
return 1;
}
+/* Comparison functions used by qsort() in the be_sort() converter below. They
+ * compare two big-endian unsigned integers of a fixed width. Since the values
+ * are unsigned and stored in network byte order, comparing their bytes from
+ * the most significant one gives the numerical order, which is exactly what
+ * memcmp() does.
+ */
+static int sample_conv_be_sort_cmp1(const void *a, const void *b)
+{
+ return memcmp(a, b, 1);
+}
+
+static int sample_conv_be_sort_cmp2(const void *a, const void *b)
+{
+ return memcmp(a, b, 2);
+}
+
+static int sample_conv_be_sort_cmp4(const void *a, const void *b)
+{
+ return memcmp(a, b, 4);
+}
+
+static int sample_conv_be_sort_cmp8(const void *a, const void *b)
+{
+ return memcmp(a, b, 8);
+}
+
+static int sample_conv_be_sort_check(struct arg *args, struct sample_conv *conv,
+ const char *file, int line, char **err)
+{
+ switch (args[0].data.sint) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ memprintf(err, "element size must be 1, 2, 4 or 8 (got %lld)", args[0].data.sint);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Sorts in ascending order the big-endian unsigned integers of <elem_size>
+ * bytes found in the binary input sample. The input length must be a multiple
+ * of <elem_size>, otherwise the conversion fails. This may be used to
+ * normalize a list of binary values before hashing it, e.g. the cipher list of
+ * a TLS client hello.
+ * Arguments: elem_size (1, 2, 4 or 8)
+ */
+static int sample_conv_be_sort(const struct arg *args, struct sample *smp, void *private)
+{
+ struct buffer *trash = get_best_trash_chunk(&smp->data.u.str, smp->data.u.str.data);
+ size_t elem_size = args[0].data.sint;
+ int (*cmp)(const void *, const void *);
+
+ if (!trash)
+ return 0;
+
+ if (smp->data.u.str.data % elem_size)
+ return 0;
+
+ switch (elem_size) {
+ case 1:
+ cmp = sample_conv_be_sort_cmp1;
+ break;
+ case 2:
+ cmp = sample_conv_be_sort_cmp2;
+ break;
+ case 4:
+ cmp = sample_conv_be_sort_cmp4;
+ break;
+ default:
+ cmp = sample_conv_be_sort_cmp8;
+ break;
+ }
+
+ memcpy(trash->area, smp->data.u.str.area, smp->data.u.str.data);
+ trash->data = smp->data.u.str.data;
+
+ qsort(trash->area, trash->data / elem_size, elem_size, cmp);
+
+ smp->data.u.str = *trash;
+ smp->data.type = SMP_T_BIN;
+ smp->flags &= ~SMP_F_CONST;
+ return 1;
+}
+
/* check and/or preset the optional argument of has_ctl() */
static int sample_conv_hasctl_check(struct arg *args, struct sample_conv *conv,
const char *file, int line, char **err)
{ "be2dec", sample_conv_be2dec, ARG3(1,STR,SINT,SINT), sample_conv_2dec_check, SMP_T_BIN, SMP_T_STR },
{ "le2dec", sample_conv_le2dec, ARG3(1,STR,SINT,SINT), sample_conv_2dec_check, SMP_T_BIN, SMP_T_STR },
{ "be2hex", sample_conv_be2hex, ARG3(1,STR,SINT,SINT), sample_conv_be2hex_check, SMP_T_BIN, SMP_T_STR },
+ { "be_sort", sample_conv_be_sort, ARG1(1,SINT), sample_conv_be_sort_check, SMP_T_BIN, SMP_T_BIN },
{ "has_ctl", sample_conv_hasctl, ARG1(0,STR), sample_conv_hasctl_check, SMP_T_BIN, SMP_T_BOOL },
{ "hex", sample_conv_bin2hex, 0, NULL, SMP_T_BIN, SMP_T_STR },
{ "hex2i", sample_conv_hex2int, 0, NULL, SMP_T_STR, SMP_T_SINT },