MINOR: http_ext: add rfc7239_n2nn converter
Adding new http converter: rfc7239_n2nn.
Takes a string representing 7239 forwarded header node (extracted from
either 'for' or 'by' 7239 header fields) as input and translates it
to either ipv4 address, ipv6 address or str ('_' prefixed if obfuscated
or "unknown" if unknown), according to 7239RFC.
Example:
# extract 'for' field from forwarded header, extract nodename from
# resulting node identifier and store the result in req.fnn
http-request set-var(req.fnn) req.hdr(forwarded),rfc7239_field(for),rfc7239_n2nn
#input: "for=\"127.0.0.1:9999\""
# output: 127.0.0.1
#input: "for=\"_name:_port\""
# output: "_name"
Depends on:
- "MINOR: http_ext: introduce http ext converters"
diff --git a/doc/configuration.txt b/doc/configuration.txt
index b0c64a5..37c2d33 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -17251,6 +17251,23 @@
#input: "proto=https;host=\"haproxy.org:80\";for=\"127.0.0.1:9999\""
# output: "127.0.0.1:9999"
+rfc7239_n2nn
+ Converts RFC7239 node (provided by 'for' or 'by' 7239 header fields)
+ into its corresponding nodename final form:
+ - ipv4 address
+ - ipv6 address
+ - 'unknown'
+ - '_obfs' identifier
+
+ Example:
+ # extract 'for' field from forwarded header, extract nodename from
+ # resulting node identifier and store the result in req.fnn
+ http-request set-var(req.fnn) req.hdr(forwarded),rfc7239_field(for),rfc7239_n2nn
+ #input: "for=\"127.0.0.1:9999\""
+ # output: 127.0.0.1
+ #input: "for=\"_name:_port\""
+ # output: "_name"
+
add(<value>)
Adds <value> to the input value of type signed integer, and returns the
result as a signed integer. <value> can be a numeric value or a variable
diff --git a/src/http_ext.c b/src/http_ext.c
index ba8bec8..3681bd0 100644
--- a/src/http_ext.c
+++ b/src/http_ext.c
@@ -1433,10 +1433,58 @@
return 1;
}
+/* input: substring representing 7239 forwarded header node
+ * output: forwarded header nodename translated to either
+ * ipv4 address, ipv6 address or str
+ * ('_' prefix if obfuscated, or "unknown" if unknown)
+ */
+static int sample_conv_7239_n2nn(const struct arg *args, struct sample *smp, void *private)
+{
+ struct ist input = ist2(smp->data.u.str.area, smp->data.u.str.data);
+ struct forwarded_header_node ctx;
+ struct buffer *output;
+
+ if (http_7239_extract_node(&input, &ctx, 1) == 0)
+ return 0; /* could not extract node */
+ switch (ctx.nodename.type) {
+ case FORWARDED_HEADER_UNK:
+ output = get_trash_chunk();
+ chunk_appendf(output, "unknown");
+ smp->flags &= ~SMP_F_CONST;
+ smp->data.type = SMP_T_STR;
+ smp->data.u.str = *output;
+ break;
+ case FORWARDED_HEADER_OBFS:
+ output = get_trash_chunk();
+ chunk_appendf(output, "_"); /* append obfs prefix */
+ chunk_istcat(output, ctx.nodename.obfs);
+ smp->flags &= ~SMP_F_CONST;
+ smp->data.type = SMP_T_STR;
+ smp->data.u.str = *output;
+ break;
+ case FORWARDED_HEADER_IP:
+ if (ctx.nodename.ip.ss_family == AF_INET) {
+ smp->data.type = SMP_T_IPV4;
+ smp->data.u.ipv4 = ((struct sockaddr_in *)&ctx.nodename.ip)->sin_addr;
+ }
+ else if (ctx.nodename.ip.ss_family == AF_INET6) {
+ smp->data.type = SMP_T_IPV6;
+ smp->data.u.ipv6 = ((struct sockaddr_in6 *)&ctx.nodename.ip)->sin6_addr;
+ }
+ else
+ return 0; /* unsupported */
+ break;
+ default:
+ return 0; /* unsupported */
+ }
+ return 1;
+}
+
/* Note: must not be declared <const> as its list will be overwritten */
static struct sample_conv_kw_list sample_conv_kws = {ILH, {
{ "rfc7239_is_valid", sample_conv_7239_valid, 0, NULL, SMP_T_STR, SMP_T_BOOL},
{ "rfc7239_field", sample_conv_7239_field, ARG1(1,STR), NULL, SMP_T_STR, SMP_T_STR},
+ { "rfc7239_n2nn", sample_conv_7239_n2nn, 0, NULL, SMP_T_STR, SMP_T_ANY},
{ NULL, NULL, 0, 0, 0 },
}};