[exim-cvs] Expansions: mask_n operator

Startseite
Nachricht löschen
Nachricht beantworten
Autor: Exim Git Commits Mailing List
Datum:  
To: exim-cvs
Betreff: [exim-cvs] Expansions: mask_n operator
Gitweb: https://git.exim.org/exim.git/commitdiff/c51f713eebe21071f22d0830fdaeb274b1a77059
Commit:     c51f713eebe21071f22d0830fdaeb274b1a77059
Parent:     b003ce30f0038c2042303d18fc24f278de06a1f5
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sun Aug 8 17:34:49 2021 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sun Aug 8 17:34:49 2021 +0100


    Expansions: mask_n operator
---
 doc/doc-docbook/spec.xfpt    | 17 ++++++++++++++---
 doc/doc-txt/NewStuff         |  2 ++
 src/src/expand.c             | 23 +++++++++++++++++------
 test/scripts/0000-Basic/0002 |  2 ++
 test/stdout/0002             |  2 ++
 5 files changed, 37 insertions(+), 9 deletions(-)


diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 0385de6..e766b69 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -11228,7 +11228,8 @@ empty.
The parsing correctly handles SMTPUTF8 Unicode in the string.


-.vitem &*${mask:*&<&'IP&~address'&>&*/*&<&'bit&~count'&>&*}*&
+.vitem &*${mask:*&<&'IP&~address'&>&*/*&<&'bit&~count'&>&*}*& &&&
+       &*${mask_n:*&<&'IP&~address'&>&*/*&<&'bit&~count'&>&*}*&
 .cindex "masked IP address"
 .cindex "IP address" "masking"
 .cindex "CIDR notation"
@@ -11242,8 +11243,14 @@ the result back to text, with mask appended. For example,
 .code
 ${mask:10.111.131.206/28}
 .endd
-returns the string &"10.111.131.192/28"&. Since this operation is expected to
-be mostly used for looking up masked addresses in files, the result for an IPv6
+returns the string &"10.111.131.192/28"&.
+
+Since this operation is expected to
+be mostly used for looking up masked addresses in files, the
+.new
+normal
+.wen
+result for an IPv6
 address uses dots to separate components instead of colons, because colon
 terminates a key string in lsearch files. So, for example,
 .code
@@ -11253,6 +11260,10 @@ returns the string
 .code
 3ffe.ffff.836f.0a00.000a.0800.2000.0000/99
 .endd
+.new
+If the optional form &*mask_n*& is used, IPv6 address result are instead
+returned in normailsed form, using colons and with zero-compression.
+.wen
 Letters in IPv6 addresses are always output in lower case.



diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 478446b..1d6190b 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -11,6 +11,8 @@ Version 4.96

1. A new ACL condition: seen. Records/tests a timestamp against a key.

+ 2. A variant of the "mask" expansion operator to give normalised IPv6.
+

 Version 4.95
 ------------
diff --git a/src/src/expand.c b/src/src/expand.c
index 4fb9355..83c0ad0 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -7333,11 +7333,11 @@ while (*s)
         int count;
         uschar *endptr;
         int binary[4];
-        int mask, maskoffset;
-        int type = string_is_ip_address(sub, &maskoffset);
+        int type, mask, maskoffset;
+    BOOL normalised;
         uschar buffer[64];


-        if (type == 0)
+        if ((type = string_is_ip_address(sub, &maskoffset)) == 0)
           {
           expand_string_message = string_sprintf("\"%s\" is not an IP address",
            sub);
@@ -7353,13 +7353,18 @@ while (*s)


         mask = Ustrtol(sub + maskoffset + 1, &endptr, 10);


-        if (*endptr != 0 || mask < 0 || mask > ((type == 4)? 32 : 128))
+        if (*endptr || mask < 0 || mask > (type == 4 ? 32 : 128))
           {
           expand_string_message = string_sprintf("mask value too big in \"%s\"",
             sub);
           goto EXPAND_FAILED;
           }


+    /* If an optional 'n' was given, ipv6 gets normalised output:
+    colons rather than dots, and zero-compressed. */
+
+    normalised = arg && *arg == 'n';
+
         /* Convert the address to binary integer(s) and apply the mask */


         sub[maskoffset] = 0;
@@ -7368,8 +7373,14 @@ while (*s)


         /* Convert to masked textual format and add to output. */


-        yield = string_catn(yield, buffer,
-          host_nmtoa(count, binary, mask, buffer, '.'));
+    if (type == 4 || !normalised)
+      yield = string_catn(yield, buffer,
+        host_nmtoa(count, binary, mask, buffer, '.'));
+    else
+      {
+      ipv6_nmtoa(binary, buffer);
+      yield = string_fmt_append(yield, "%s/%d", buffer, mask);
+      }
         continue;
         }


diff --git a/test/scripts/0000-Basic/0002 b/test/scripts/0000-Basic/0002
index cc289e0..db3eae6 100644
--- a/test/scripts/0000-Basic/0002
+++ b/test/scripts/0000-Basic/0002
@@ -248,6 +248,8 @@ mask:   ${mask:192.168.10.206/33}
 mask:   ${mask:192.168.10.206/0}
 mask:   ${mask:192.168.10.206}
 mask:   ${mask:a.b.c.d}
+mask:   ${mask:2a00:2:3:4:5:6:7:8/79}
+mask_n: ${mask_n:2a00:2:3:4:5:6:7:8/79}
 ipv6denorm: ${ipv6denorm:::1}
 ipv6denorm: ${ipv6denorm:fe00::1}
 ipv6denorm: ${ipv6denorm:192.168.0.1}
diff --git a/test/stdout/0002 b/test/stdout/0002
index 0b9a95c..5c8c252 100644
--- a/test/stdout/0002
+++ b/test/stdout/0002
@@ -230,6 +230,8 @@ newline    tab\134backslash ~tilde\177DEL\200\201.

> mask: 0.0.0.0/0
> Failed: missing mask value in "192.168.10.206"
> Failed: "a.b.c.d" is not an IP address

+> mask: 2a00.0002.0003.0004.0004.0000.0000.0000/79
+> mask_n: 2a00:2:3:4:4::/79
> ipv6denorm: 0000:0000:0000:0000:0000:0000:0000:0001
> ipv6denorm: fe00:0000:0000:0000:0000:0000:0000:0001
> ipv6denorm: 0000:0000:0000:0000:0000:ffff:c0a8:0001