summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilip Hazel <ph10@hermes.cam.ac.uk>2005-08-09 13:31:52 +0000
committerPhilip Hazel <ph10@hermes.cam.ac.uk>2005-08-09 13:31:52 +0000
commit7cd1141be4e551e80514c38662ec6e8209608205 (patch)
tree22b376ac572c8847b3ccf8ee48d1db95599968d9 /src
parent2d280592a7f859d1e06738d86c3bc43382f1b791 (diff)
Allow port setting on lists of hosts in manualroute, queryprogram,
fallback_hosts, and "hosts" in smtp.
Diffstat (limited to 'src')
-rw-r--r--src/exim_monitor/em_main.c4
-rw-r--r--src/src/exim.c4
-rw-r--r--src/src/functions.h5
-rw-r--r--src/src/host.c59
-rw-r--r--src/src/routers/rf_lookup_hostlist.c25
-rw-r--r--src/src/spool_in.c6
-rw-r--r--src/src/transports/smtp.c52
7 files changed, 121 insertions, 34 deletions
diff --git a/src/exim_monitor/em_main.c b/src/exim_monitor/em_main.c
index cee1fd09a..b3b27a24f 100644
--- a/src/exim_monitor/em_main.c
+++ b/src/exim_monitor/em_main.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/exim_monitor/em_main.c,v 1.2 2005/01/04 10:00:42 ph10 Exp $ */
+/* $Cambridge: exim/src/exim_monitor/em_main.c,v 1.3 2005/08/09 13:31:52 ph10 Exp $ */
/*************************************************
* Exim Monitor *
@@ -200,7 +200,7 @@ Returns: 0 if there is no port, else the port number.
*/
int
-host_extract_port(uschar *address)
+host_address_extract_port(uschar *address)
{
int skip = -3; /* Skip 3 dots in IPv4 addresses */
address--;
diff --git a/src/src/exim.c b/src/src/exim.c
index 98b01511d..06e01399a 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/exim.c,v 1.23 2005/08/01 13:20:28 ph10 Exp $ */
+/* $Cambridge: exim/src/src/exim.c,v 1.24 2005/08/09 13:31:52 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -599,7 +599,7 @@ Returns: the port, or zero if there isn't one
static int
check_port(uschar *address)
{
-int port = host_extract_port(address);
+int port = host_address_extract_port(address);
if (string_is_ip_address(address, NULL) == 0)
{
fprintf(stderr, "exim abandoned: \"%s\" is not an IP address\n", address);
diff --git a/src/src/functions.h b/src/src/functions.h
index 7e61c92f6..6d1f5cd8c 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/functions.h,v 1.18 2005/08/02 15:19:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/functions.h,v 1.19 2005/08/09 13:31:52 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -107,19 +107,20 @@ extern BOOL filter_system_interpret(address_item **, uschar **);
extern void header_add(int, char *, ...);
extern int header_checkname(header_line *, BOOL);
extern BOOL header_match(uschar *, BOOL, BOOL, string_item *, int, ...);
+extern int host_address_extract_port(uschar *);
extern uschar *host_and_ident(BOOL);
extern int host_aton(uschar *, int *);
extern void host_build_hostlist(host_item **, uschar *, BOOL);
extern ip_address_item *host_build_ifacelist(uschar *, uschar *);
extern void host_build_log_info(void);
extern void host_build_sender_fullhost(void);
-extern int host_extract_port(uschar *);
extern BOOL host_find_byname(host_item *, uschar *, uschar **, BOOL);
extern int host_find_bydns(host_item *, uschar *, int, uschar *, uschar *,
uschar *,uschar **, BOOL *);
extern ip_address_item *host_find_interfaces(void);
extern BOOL host_is_in_net(uschar *, uschar *, int);
extern BOOL host_is_tls_on_connect_port(int);
+extern int host_item_get_port(host_item *);
extern void host_mask(int, int *, int);
extern int host_name_lookup(void);
extern int host_nmtoa(int, int *, int, uschar *, int);
diff --git a/src/src/host.c b/src/src/host.c
index d8f560788..9f3a06870 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -1,4 +1,4 @@
-/* $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.12 2005/08/09 13:31:52 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -237,7 +237,7 @@ Returns: 0 if there is no port, else the port number. If there's a syntax
*/
int
-host_extract_port(uschar *address)
+host_address_extract_port(uschar *address)
{
int port = 0;
uschar *endptr;
@@ -281,6 +281,59 @@ return port;
}
+/*************************************************
+* 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 */
@@ -495,7 +548,7 @@ ip_address_item *next;
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);
diff --git a/src/src/routers/rf_lookup_hostlist.c b/src/src/routers/rf_lookup_hostlist.c
index 5646315cb..3e7eee137 100644
--- a/src/src/routers/rf_lookup_hostlist.c
+++ b/src/src/routers/rf_lookup_hostlist.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/routers/rf_lookup_hostlist.c,v 1.3 2005/01/11 15:51:03 ph10 Exp $ */
+/* $Cambridge: exim/src/src/routers/rf_lookup_hostlist.c,v 1.4 2005/08/09 13:31:53 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -27,6 +27,12 @@ case, MX records are looked up for the name, and the list of hosts obtained
replaces the incoming "host". In other words, "x/MX" is shorthand for "those
hosts pointed to by x's MX records".
+It is also possible for a port to be specified along with the host name or IP
+address. The syntax is to add ":port" on to the end. This doesn't work with
+IPv6 addresses, so we allow IP addresses to be enclosed in [] in order to make
+this work. The specification of the port must come last, that is, after "/MX"
+if that is present.
+
Arguments:
rblock the router block
addr the address being routed
@@ -61,7 +67,7 @@ prev = NULL;
for (h = addr->host_list; h != NULL; prev = h, h = next_h)
{
uschar *canonical_name;
- int rc, len;
+ int rc, len, port;
next_h = h->next;
if (h->address != NULL) continue;
@@ -69,6 +75,11 @@ for (h = addr->host_list; h != NULL; prev = h, h = next_h)
DEBUG(D_route|D_host_lookup)
debug_printf("finding IP address for %s\n", h->name);
+ /* Handle any port setting that may be on the name; it will be removed
+ from the end of the name. */
+
+ port = host_item_get_port(h);
+
/* If the name ends with "/MX", we interpret it to mean "the list of hosts
pointed to by MX records with this name". */
@@ -78,7 +89,7 @@ for (h = addr->host_list; h != NULL; prev = h, h = next_h)
DEBUG(D_route|D_host_lookup)
debug_printf("doing DNS MX lookup for %s\n", h->name);
- h->name[len-3] = 0;
+ h->name = string_copyn(h->name, len - 3);
rc = host_find_bydns(h,
ignore_target_hosts,
HOST_FIND_BY_MX, /* look only for MX records */
@@ -159,6 +170,14 @@ for (h = addr->host_list; h != NULL; prev = h, h = next_h)
return DEFER;
}
+ /* Deal with a port setting */
+
+ if (port != PORT_NONE)
+ {
+ host_item *hh;
+ for (hh = h; hh != next_h; hh = hh->next) hh->port = port;
+ }
+
/* A local host gets chopped, with its successors, if there are previous
hosts. Otherwise the self option is used. If it is set to "send", any
subsequent hosts that are also the local host do NOT get chopped. */
diff --git a/src/src/spool_in.c b/src/src/spool_in.c
index 6efe5aa27..8e56677bd 100644
--- a/src/src/spool_in.c
+++ b/src/src/spool_in.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/spool_in.c,v 1.12 2005/06/27 14:29:44 ph10 Exp $ */
+/* $Cambridge: exim/src/src/spool_in.c,v 1.13 2005/08/09 13:31:53 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -448,13 +448,13 @@ for (;;)
else if (Ustrncmp(big_buffer, "-host_address", 13) == 0)
{
- sender_host_port = host_extract_port(big_buffer + 14);
+ sender_host_port = host_address_extract_port(big_buffer + 14);
sender_host_address = string_copy(big_buffer + 14);
}
else if (Ustrncmp(big_buffer, "-interface_address", 18) == 0)
{
- interface_port = host_extract_port(big_buffer + 19);
+ interface_port = host_address_extract_port(big_buffer + 19);
interface_address = string_copy(big_buffer + 19);
}
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index c16e620b3..a503d8f13 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/transports/smtp.c,v 1.16 2005/08/08 15:02:48 ph10 Exp $ */
+/* $Cambridge: exim/src/src/transports/smtp.c,v 1.17 2005/08/09 13:31:53 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -329,8 +329,8 @@ this particular type of timeout.
Returns: nothing
*/
-static
-void set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
+static void
+set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
BOOL pass_message)
{
address_item *addr;
@@ -505,14 +505,14 @@ if (addr->message != NULL)
}
else
{
- log_write(0, LOG_MAIN, "%s [%s]: %s",
- host->name,
- host->address,
- strerror(addr->basic_errno));
- deliver_msglog("%s %s [%s]: %s\n",
- tod_stamp(tod_log),
- host->name,
- host->address,
+ uschar *msg =
+ ((log_extra_selector & LX_outgoing_port) != 0)?
+ string_sprintf("%s [%s]:%d", host->name, host->address,
+ (host->port == PORT_NONE)? 25 : host->port)
+ :
+ string_sprintf("%s [%s]", host->name, host->address);
+ log_write(0, LOG_MAIN, "%s %s", msg, strerror(addr->basic_errno));
+ deliver_msglog("%s %s %s\n", tod_stamp(tod_log), msg,
strerror(addr->basic_errno));
}
}
@@ -2206,14 +2206,6 @@ for (cutoff_retry = 0; expired &&
uschar *retry_message_key = NULL;
uschar *serialize_key = NULL;
- /* Set up a string for adding to the retry key if the port number is not
- the standard SMTP port. A host may have its own port setting that overrides
- the default. */
-
- pistring = string_sprintf(":%d", (host->port == PORT_NONE)?
- port : host->port);
- if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
-
/* Default next host is next host. :-) But this can vary if the
hosts_max_try limit is hit (see below). It may also be reset if a host
address is looked up here (in case the host was multihomed). */
@@ -2243,6 +2235,8 @@ for (cutoff_retry = 0; expired &&
if (host->address == NULL)
{
+ int new_port;
+ host_item *hh;
uschar *canonical_name;
if (host->status >= hstatus_unusable)
@@ -2254,6 +2248,13 @@ for (cutoff_retry = 0; expired &&
DEBUG(D_transport) debug_printf("getting address for %s\n", host->name);
+ /* The host name is permitted to have an attached port. Find it, and
+ strip it from the name. Just remember it for now. */
+
+ new_port = host_item_get_port(host);
+
+ /* Count hosts looked up */
+
hosts_looked_up++;
/* Find by name if so configured, or if it's an IP address. We don't
@@ -2270,6 +2271,11 @@ for (cutoff_retry = 0; expired &&
&canonical_name, NULL);
}
+ /* Update the host (and any additional blocks, resulting from
+ multihoming) with a host-specific port, if any. */
+
+ for (hh = host; hh != nexthost; hh = hh->next) hh->port = new_port;
+
/* Failure to find the host at this time (usually DNS temporary failure)
is really a kind of routing failure rather than a transport failure.
Therefore we add a retry item of the routing kind, not to stop us trying
@@ -2363,6 +2369,14 @@ for (cutoff_retry = 0; expired &&
deliver_host = host->name;
deliver_host_address = host->address;
+ /* Set up a string for adding to the retry key if the port number is not
+ the standard SMTP port. A host may have its own port setting that overrides
+ the default. */
+
+ pistring = string_sprintf(":%d", (host->port == PORT_NONE)?
+ port : host->port);
+ if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
+
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
string changes upon expansion, we must add it to the key that is used for
retries, because connections to the same host from a different interface