-/* $Cambridge: exim/src/src/host.c,v 1.11 2005/08/02 09:01:44 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.13 2005/08/22 15:28:20 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*/
int
-host_extract_port(uschar *address)
+host_address_extract_port(uschar *address)
{
int port = 0;
uschar *endptr;
}
+/*************************************************
+* Get port from a host item's name *
+*************************************************/
+
+/* This function is called when finding the IP address for a host that is in a
+list of hosts explicitly configured, such as in the manualroute router, or in a
+fallback hosts list. We see if there is a port specification at the end of the
+host name, and if so, remove it. A minimum length of 3 is required for the
+original name; nothing shorter is recognized as having a port.
+
+We test for a name ending with a sequence of digits; if preceded by colon we
+have a port if the character before the colon is ] and the name starts with [
+or if there are no other colons in the name (i.e. it's not an IPv6 address).
+
+Arguments: pointer to the host item
+Returns: a port number or PORT_NONE
+*/
+
+int
+host_item_get_port(host_item *h)
+{
+uschar *p;
+int port, x;
+int len = Ustrlen(h->name);
+
+if (len < 3 || (p = h->name + len - 1, !isdigit(*p))) return PORT_NONE;
+
+/* Extract potential port number */
+
+port = *p-- - '0';
+x = 10;
+
+while (p > h->name + 1 && isdigit(*p))
+ {
+ port += (*p-- - '0') * x;
+ x *= 10;
+ }
+
+/* The smallest value of p at this point is h->name + 1. */
+
+if (*p != ':') return PORT_NONE;
+
+if (p[-1] == ']' && h->name[0] == '[')
+ h->name = string_copyn(h->name + 1, p - h->name - 2);
+else if (Ustrchr(h->name, ':') == p)
+ h->name = string_copyn(h->name, p - h->name);
+else return PORT_NONE;
+
+DEBUG(D_route|D_host_lookup) debug_printf("host=%s port=%d\n", h->name, port);
+return port;
+}
+
+
#ifndef STAND_ALONE /* Omit when standalone testing */
else
{
int len;
+ BOOL no_helo = FALSE;
+
+ /* Comparing a HELO name to a host name is easy */
+
if (sender_helo_name == NULL ||
- strcmpic(sender_host_name, sender_helo_name) == 0 ||
- (sender_helo_name[0] == '[' &&
- sender_helo_name[(len=Ustrlen(sender_helo_name))-1] == ']' &&
- strncmpic(sender_helo_name+1, sender_host_address, len - 2) == 0))
+ strcmpic(sender_host_name, sender_helo_name) == 0)
+ no_helo = TRUE;
+
+ /* If HELO/EHLO was followed by an IP literal, it's much more messy because
+ of two features of IPv6. Firstly, there's the "IPv6:" prefix (Exim is liberal
+ and doesn't require this, for historical reasons). Secondly, an IPv6 address
+ may not be given in canonical form, so we have to canonicize it before
+ comparing. As it happens, the code works for both IPv4 and IPv6. */
+
+ else if (sender_helo_name[0] == '[' &&
+ sender_helo_name[(len=Ustrlen(sender_helo_name))-1] == ']')
+ {
+ uschar *helo_ip;
+ int offset = 1;
+
+ if (strncmpic(sender_helo_name+1, US"IPv6:",5) == 0) offset += 5;
+ helo_ip = string_copyn(sender_helo_name + offset, len - offset - 1);
+
+ if (string_is_ip_address(helo_ip, NULL) != 0)
+ {
+ int x[4];
+ int size;
+ size = host_aton(helo_ip, x);
+ helo_ip = store_get(48); /* large enough for full IPv6 */
+ (void)host_nmtoa(size, x, -1, helo_ip, ':');
+ if (strcmpic(helo_ip, sender_host_address) == 0) no_helo = TRUE;
+ }
+ }
+
+ if (no_helo)
{
sender_fullhost = string_sprintf("%s %s", sender_host_name, address);
sender_rcvhost = (sender_ident == NULL)?
while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
{
- int port = host_extract_port(s); /* Leaves just the IP address */
+ int port = host_address_extract_port(s); /* Leaves just the IP address */
if (string_is_ip_address(s, NULL) == 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s",
s, name);