]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: http_ext: add rfc7239_n2nn converter
authorAurelien DARRAGON <adarragon@haproxy.com>
Fri, 30 Dec 2022 15:45:42 +0000 (16:45 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 27 Jan 2023 14:18:59 +0000 (15:18 +0100)
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"

doc/configuration.txt
src/http_ext.c

index b0c64a5bf97be7851acf254adc84676795838301..37c2d331d5cca1966f0734c1c36b98b645df0540 100644 (file)
@@ -17251,6 +17251,23 @@ rfc7239_field(<field>)
     #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
index ba8bec8e000a9681149aaf32c2f70fef356c7080..3681bd0791aba794e1e1beec848e2cb798d7a697 100644 (file)
@@ -1433,10 +1433,58 @@ static int sample_conv_7239_field(const struct arg *args, struct sample *smp, vo
        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 },
 }};