diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/src/expand.c | 37 | ||||
-rw-r--r-- | src/src/functions.h | 2 | ||||
-rw-r--r-- | src/src/host.c | 67 |
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 * |