X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/7a546ad529bc715e345141261097737a986af03c..d7d7b7b91dd75cec636fc144da7e27eed860f971:/src/src/host.c diff --git a/src/src/host.c b/src/src/host.c index 7df1f1428..317d257bb 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/host.c,v 1.15 2005/09/19 10:13:39 ph10 Exp $ */ +/* $Cambridge: exim/src/src/host.c,v 1.20 2006/02/07 11:19:00 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2006 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or @@ -167,8 +167,13 @@ Returns: a hostent structure or NULL for an error static struct hostent * host_fake_gethostbyname(uschar *name, int af, int *error_num) { -int ipa; +#if HAVE_IPV6 int alen = (af == AF_INET)? sizeof(struct in_addr):sizeof(struct in6_addr); +#else +int alen = sizeof(struct in_addr); +#endif + +int ipa; uschar *lname = name; uschar *adds; uschar **alist; @@ -530,8 +535,9 @@ as follows: (a) No sender_host_name or sender_helo_name: "[ip address]" (b) Just sender_host_name: "host_name [ip address]" -(c) Just sender_helo_name: "(helo_name) [ip address]" -(d) The two are identical: "host_name [ip address]" +(c) Just sender_helo_name: "(helo_name) [ip address]" unless helo is IP + in which case: "[ip address}" +(d) The two are identical: "host_name [ip address]" includes helo = IP (e) The two are different: "host_name (helo_name) [ip address]" If log_incoming_port is set, the sending host's port number is added to the IP @@ -552,7 +558,9 @@ Returns: nothing void host_build_sender_fullhost(void) { +BOOL show_helo = TRUE; uschar *address; +int len; int old_pool = store_pool; if (sender_host_address == NULL) return; @@ -568,6 +576,43 @@ address = string_sprintf("[%s]:%d", sender_host_address, sender_host_port); if ((log_extra_selector & LX_incoming_port) == 0 || sender_host_port <= 0) *(Ustrrchr(address, ':')) = 0; +/* If there's no EHLO/HELO data, we can't show it. */ + +if (sender_helo_name == NULL) show_helo = FALSE; + +/* If HELO/EHLO was followed by an IP literal, it's 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, IPv6 addresses may not +be given in canonical form, so we have to canonicize them 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] == ']') + { + int offset = 1; + uschar *helo_ip; + + if (strncmpic(sender_helo_name + 1, US"IPv6:", 5) == 0) offset += 5; + if (strncmpic(sender_helo_name + 1, US"IPv4:", 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], y[4]; + int sizex, sizey; + uschar ipx[48], ipy[48]; /* large enough for full IPv6 */ + + sizex = host_aton(helo_ip, x); + sizey = host_aton(sender_host_address, y); + + (void)host_nmtoa(sizex, x, -1, ipx, ':'); + (void)host_nmtoa(sizey, y, -1, ipy, ':'); + + if (strcmpic(ipx, ipy) == 0) show_helo = FALSE; + } + } + /* Host name is not verified */ if (sender_host_name == NULL) @@ -583,7 +628,7 @@ if (sender_host_name == NULL) sender_rcvhost = string_cat(NULL, &size, &ptr, address, adlen); - if (sender_ident != NULL || sender_helo_name != NULL || portptr != NULL) + if (sender_ident != NULL || show_helo || portptr != NULL) { int firstptr; sender_rcvhost = string_cat(sender_rcvhost, &size, &ptr, US" (", 2); @@ -593,7 +638,7 @@ if (sender_host_name == NULL) sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, US"port=", portptr + 1); - if (sender_helo_name != NULL) + if (show_helo) sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, (firstptr == ptr)? US"helo=" : US" helo=", sender_helo_name); @@ -612,54 +657,15 @@ if (sender_host_name == NULL) store_reset(sender_rcvhost + ptr + 1); } -/* Host name is known and verified. */ +/* Host name is known and verified. Unless we've already found that the HELO +data matches the IP address, compare it with the name. */ 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) - 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 (show_helo && strcmpic(sender_host_name, sender_helo_name) == 0) + show_helo = FALSE; - 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)? - string_sprintf("%s (%s)", sender_host_name, address) : - string_sprintf("%s (%s ident=%s)", sender_host_name, address, - sender_ident); - } - else + if (show_helo) { sender_fullhost = string_sprintf("%s (%s) %s", sender_host_name, sender_helo_name, address); @@ -669,6 +675,14 @@ else string_sprintf("%s\n\t(%s helo=%s ident=%s)", sender_host_name, address, sender_helo_name, sender_ident); } + else + { + sender_fullhost = string_sprintf("%s %s", sender_host_name, address); + sender_rcvhost = (sender_ident == NULL)? + string_sprintf("%s (%s)", sender_host_name, address) : + string_sprintf("%s (%s ident=%s)", sender_host_name, address, + sender_ident); + } } store_pool = old_pool; @@ -760,11 +774,16 @@ ip_address_item *next; while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) { + int ipv; int port = host_address_extract_port(s); /* Leaves just the IP address */ - if (string_is_ip_address(s, NULL) == 0) + if ((ipv = string_is_ip_address(s, NULL)) == 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s", s, name); + /* Skip IPv6 addresses if IPv6 is disabled. */ + + if (disable_ipv6 && ipv == 6) continue; + /* This use of strcpy() is OK because we have checked that s is a valid IP address above. The field in the ip_address_item is large enough to hold an IPv6 address. */ @@ -1822,13 +1841,10 @@ for (hname = sender_host_name; hname != NULL; hname = *aliases++) if ((rc = host_find_byname(&h, NULL, NULL, FALSE)) == HOST_FOUND) { host_item *hh; - uschar *address_ipv4 = (Ustrncmp(sender_host_address, "::ffff:", 7) == 0)? - sender_host_address + 7 : sender_host_address; HDEBUG(D_host_lookup) debug_printf("checking addresses for %s\n", hname); for (hh = &h; hh != NULL; hh = hh->next) { - if ((Ustrcmp(hh->address, (Ustrchr(hh->address, ':') == NULL)? - address_ipv4 : sender_host_address)) == 0) + if (host_is_in_net(hh->address, sender_host_address, 0)) { HDEBUG(D_host_lookup) debug_printf(" %s OK\n", hh->address); ok = TRUE; @@ -1954,17 +1970,17 @@ if (running_in_test_harness) return HOST_FIND_AGAIN; } -/* In an IPv6 world, we need to scan for both kinds of address, so go round the -loop twice. Note that we have ensured that AF_INET6 is defined even in an IPv4 -world, which makes for slightly tidier code. However, if dns_ipv4_lookup -matches the domain, we also just do IPv4 lookups here (except when testing -standalone). */ +/* In an IPv6 world, unless IPv6 has been disabled, we need to scan for both +kinds of address, so go round the loop twice. Note that we have ensured that +AF_INET6 is defined even in an IPv4 world, which makes for slightly tidier +code. However, if dns_ipv4_lookup matches the domain, we also just do IPv4 +lookups here (except when testing standalone). */ #if HAVE_IPV6 #ifndef STAND_ALONE - if (dns_ipv4_lookup != NULL && + if (disable_ipv6 || (dns_ipv4_lookup != NULL && match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN, - TRUE, NULL) == OK) + TRUE, NULL) == OK)) { af = AF_INET; times = 1; } else #endif /* STAND_ALONE */ @@ -2238,18 +2254,18 @@ if (allow_ip && string_is_ip_address(host->name, NULL) != 0) return HOST_FOUND; } -/* On an IPv6 system, go round the loop up to three times, looking for A6 and -AAAA records the first two times. However, unless doing standalone testing, we -force an IPv4 lookup if the domain matches dns_ipv4_lookup is set. Since A6 -records look like being abandoned, support them only if explicitly configured -to do so. On an IPv4 system, go round the loop once only, looking only for A -records. */ +/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to three +times, looking for A6 and AAAA records the first two times. However, unless +doing standalone testing, we force an IPv4 lookup if the domain matches +dns_ipv4_lookup is set. Since A6 records look like being abandoned, support +them only if explicitly configured to do so. On an IPv4 system, go round the +loop once only, looking only for A records. */ #if HAVE_IPV6 #ifndef STAND_ALONE - if (dns_ipv4_lookup != NULL && + if (disable_ipv6 || (dns_ipv4_lookup != NULL && match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN, - TRUE, NULL) == OK) + TRUE, NULL) == OK)) i = 0; /* look up A records only */ else #endif /* STAND_ALONE */ @@ -2882,10 +2898,14 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ADDITIONAL); if (rr->type != T_A #if HAVE_IPV6 - && rr->type != T_AAAA - #ifdef SUPPORT_A6 - && rr->type != T_A6 - #endif + && ( disable_ipv6 || + ( + rr->type != T_AAAA + #ifdef SUPPORT_A6 + && rr->type != T_A6 + #endif + ) + ) #endif ) continue;