summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/src/expand.c37
-rw-r--r--src/src/functions.h2
-rw-r--r--src/src/host.c67
3 files changed, 98 insertions, 8 deletions
diff --git a/src/src/expand.c b/src/src/expand.c
index fbbc68154..90ffe78c0 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -210,6 +210,8 @@ static uschar *op_table_main[] = {
US"hash",
US"hex2b64",
US"hexquote",
+ US"ipv6denorm",
+ US"ipv6norm",
US"l",
US"lc",
US"length",
@@ -248,6 +250,8 @@ enum {
EOP_HASH,
EOP_HEX2B64,
EOP_HEXQUOTE,
+ EOP_IPV6DENORM,
+ EOP_IPV6NORM,
EOP_L,
EOP_LC,
EOP_LENGTH,
@@ -6406,6 +6410,39 @@ while (*s != 0)
continue;
}
+ case EOP_IPV6NORM:
+ case EOP_IPV6DENORM:
+ {
+ int type = string_is_ip_address(sub, NULL);
+ int binary[4];
+ uschar buffer[44];
+
+ switch (type)
+ {
+ case 6:
+ (void) host_aton(sub, binary);
+ break;
+
+ case 4: /* convert to IPv4-mapped IPv6 */
+ binary[0] = binary[1] = 0;
+ binary[2] = 0x0000ffff;
+ (void) host_aton(sub, binary+3);
+ break;
+
+ case 0:
+ expand_string_message =
+ string_sprintf("\"%s\" is not an IP address", sub);
+ goto EXPAND_FAILED;
+ }
+
+ yield = string_cat(yield, &size, &ptr, buffer,
+ c == EOP_IPV6NORM
+ ? ipv6_nmtoa(binary, buffer)
+ : host_nmtoa(4, binary, -1, buffer, ':')
+ );
+ continue;
+ }
+
case EOP_ADDRESS:
case EOP_LOCAL_PART:
case EOP_DOMAIN:
diff --git a/src/src/functions.h b/src/src/functions.h
index 2fe681394..9df8030f5 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -233,6 +233,8 @@ extern int ip_tcpsocket(const uschar *, uschar **, int);
extern int ip_unixsocket(const uschar *, uschar **);
extern int ip_streamsocket(const uschar *, uschar **, int);
+extern int ipv6_nmtoa(int *, uschar *);
+
extern uschar *local_part_quote(uschar *);
extern int log_create(uschar *);
extern int log_create_as_exim(uschar *);
diff --git a/src/src/host.c b/src/src/host.c
index 429b6352c..67d33a9b8 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -1146,20 +1146,14 @@ if (count == 1)
{
j = binary[0];
for (i = 24; i >= 0; i -= 8)
- {
- sprintf(CS tt, "%d.", (j >> i) & 255);
- while (*tt) tt++;
- }
+ tt += sprintf(CS tt, "%d.", (j >> i) & 255);
}
else
- {
for (i = 0; i < 4; i++)
{
j = binary[i];
- sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
- while (*tt) tt++;
+ tt += sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
}
- }
tt--; /* lose final separator */
@@ -1175,6 +1169,63 @@ return tt - buffer;
}
+/* Like host_nmtoa() but: ipv6-only, canonical output, no mask
+
+Arguments:
+ binary points to the ints
+ buffer big enough to hold the result
+
+Returns: the number of characters placed in buffer, not counting
+ the final nul.
+*/
+
+int
+ipv6_nmtoa(int * binary, uschar * buffer)
+{
+int i, j, k;
+uschar * c = buffer;
+uschar * d;
+
+for (i = 0; i < 4; i++)
+ { /* expand to text */
+ j = binary[i];
+ c += sprintf(CS c, "%x:%x:", (j >> 16) & 0xffff, j & 0xffff);
+ }
+
+for (c = buffer, k = -1, i = 0; i < 8; i++)
+ { /* find longest 0-group sequence */
+ if (*c == '0') /* must be "0:" */
+ {
+ uschar * s = c;
+ j = i;
+ while (c[2] == '0') i++, c += 2;
+ if (i-j > k)
+ {
+ k = i-j; /* length of sequence */
+ d = s; /* start of sequence */
+ }
+ }
+ while (*++c != ':') ;
+ c++;
+ }
+
+c[-1] = '\0'; /* drop trailing colon */
+
+/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, d, d + 2*(k+1)); */
+if (k >= 0)
+ { /* collapse */
+ c = d + 2*(k+1);
+ if (d == buffer) c--; /* need extra colon */
+ *d++ = ':'; /* 1st 0 */
+ while (*d++ = *c++) ;
+ }
+else
+ d = c;
+
+return d - buffer;
+}
+
+
/*************************************************
* Check port for tls_on_connect *