~ubuntu-branches/ubuntu/raring/postfix/raring

« back to all changes in this revision

Viewing changes to src/smtp/smtp_connect.c

Tags: upstream-2.2.6
ImportĀ upstreamĀ versionĀ 2.2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
/*      that fail to complete the SMTP handshake and tries to find
20
20
/*      an alternate server when an SMTP session fails to deliver.
21
21
/*
 
22
/*      This layer also controls what sessions are retrieved from
 
23
/*      the session cache, and what sessions are saved to the cache.
 
24
/*
22
25
/*      The destination is either a host (or domain) name or a numeric
23
26
/*      address. Symbolic or numeric service port information may be
24
27
/*      appended, separated by a colon (":").
41
44
/*      IBM T.J. Watson Research
42
45
/*      P.O. Box 704
43
46
/*      Yorktown Heights, NY 10598, USA
 
47
/*
 
48
/*      Connection caching in cooperation with:
 
49
/*      Victor Duchovni
 
50
/*      Morgan Stanley
44
51
/*--*/
45
52
 
46
53
/* System library. */
47
54
 
48
55
#include <sys_defs.h>
 
56
#include <stdlib.h>
49
57
#include <sys/socket.h>
50
58
#include <netinet/in.h>
51
59
#include <arpa/inet.h>
57
65
#include <fcntl.h>
58
66
#include <ctype.h>
59
67
 
60
 
#ifdef STRCASECMP_IN_STRINGS_H
61
 
#include <strings.h>
62
 
#endif
63
 
 
64
 
#ifndef INADDR_NONE
65
 
#define INADDR_NONE 0xffffffff
 
68
#ifndef IPPORT_SMTP
 
69
#define IPPORT_SMTP 25
66
70
#endif
67
71
 
68
72
/* Utility library. */
78
82
#include <stringops.h>
79
83
#include <host_port.h>
80
84
#include <sane_connect.h>
 
85
#include <myaddrinfo.h>
 
86
#include <sock_addr.h>
81
87
 
82
88
/* Global library. */
83
89
 
84
90
#include <mail_params.h>
85
91
#include <own_inet_addr.h>
86
 
#include <debug_peer.h>
87
92
#include <deliver_pass.h>
88
93
#include <mail_error.h>
89
94
 
93
98
 
94
99
/* Application-specific. */
95
100
 
96
 
#include "smtp.h"
97
 
#include "smtp_addr.h"
 
101
#include <smtp.h>
 
102
#include <smtp_addr.h>
 
103
#include <smtp_reuse.h>
 
104
 
 
105
#define STR(x) vstring_str(x)
 
106
 
 
107
/* smtp_salvage - salvage the server reply before disconnecting */
 
108
 
 
109
static VSTRING *smtp_salvage(VSTREAM *stream)
 
110
{
 
111
    int     len = vstream_peek(stream);
 
112
    VSTRING *buf = vstring_alloc(len);
 
113
 
 
114
    /*
 
115
     * We know the server replied with 4... or 5...; salvage whatever we have
 
116
     * received in the VSTREAM buffer and sanitize any non-printable crud.
 
117
     */
 
118
    vstream_fread(stream, STR(buf), len);
 
119
    VSTRING_AT_OFFSET(buf, len);                /* XXX not public interface */
 
120
    VSTRING_TERMINATE(buf);
 
121
    translit(STR(buf), "\r\n", "  ");
 
122
    printable(STR(buf), '?');
 
123
    return (buf);
 
124
}
98
125
 
99
126
/* smtp_connect_addr - connect to explicit address */
100
127
 
101
 
static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
102
 
                                               VSTRING *why)
 
128
static SMTP_SESSION *smtp_connect_addr(const char *dest, DNS_RR *addr,
 
129
                                               unsigned port, VSTRING *why,
 
130
                                               int sess_flags)
103
131
{
104
132
    char   *myname = "smtp_connect_addr";
105
 
    struct sockaddr_in sin;
 
133
    struct sockaddr_storage ss;         /* remote */
 
134
    struct sockaddr *sa = (struct sockaddr *) & ss;
 
135
    SOCKADDR_SIZE salen = sizeof(ss);
 
136
    MAI_HOSTADDR_STR hostaddr;
106
137
    int     sock;
107
 
    INET_ADDR_LIST *addr_list;
108
138
    int     conn_stat;
109
139
    int     saved_errno;
110
140
    VSTREAM *stream;
111
141
    int     ch;
112
 
    unsigned long inaddr;
 
142
    char   *bind_addr;
 
143
    char   *bind_var;
113
144
 
114
145
    smtp_errno = SMTP_ERR_NONE;                 /* Paranoia */
115
146
 
116
147
    /*
117
148
     * Sanity checks.
118
149
     */
119
 
    if (addr->data_len > sizeof(sin.sin_addr)) {
120
 
        msg_warn("%s: skip address with length %d", myname, addr->data_len);
 
150
    if (dns_rr_to_sa(addr, port, sa, &salen) != 0) {
 
151
        msg_warn("%s: skip address type %s: %m",
 
152
                 myname, dns_strtype(addr->type));
121
153
        smtp_errno = SMTP_ERR_RETRY;
122
154
        return (0);
123
155
    }
125
157
    /*
126
158
     * Initialize.
127
159
     */
128
 
    memset((char *) &sin, 0, sizeof(sin));
129
 
    sin.sin_family = AF_INET;
130
 
 
131
 
    if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
 
160
    if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
132
161
        msg_fatal("%s: socket: %m", myname);
133
162
 
134
163
    /*
135
164
     * Allow the sysadmin to specify the source address, for example, as "-o
136
165
     * smtp_bind_address=x.x.x.x" in the master.cf file.
137
166
     */
138
 
    if (*var_smtp_bind_addr) {
139
 
        sin.sin_addr.s_addr = inet_addr(var_smtp_bind_addr);
140
 
        if (sin.sin_addr.s_addr == INADDR_NONE)
141
 
            msg_fatal("%s: bad %s parameter: %s",
142
 
                      myname, VAR_SMTP_BIND_ADDR, var_smtp_bind_addr);
143
 
        if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
144
 
            msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
145
 
        if (msg_verbose)
146
 
            msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
 
167
#ifdef HAS_IPV6
 
168
    if (sa->sa_family == AF_INET6) {
 
169
        bind_addr = var_smtp_bind_addr6;
 
170
        bind_var = VAR_SMTP_BIND_ADDR6;
 
171
    } else
 
172
#endif
 
173
    if (sa->sa_family == AF_INET) {
 
174
        bind_addr = var_smtp_bind_addr;
 
175
        bind_var = VAR_SMTP_BIND_ADDR;
 
176
    } else
 
177
        bind_var = bind_addr = "";
 
178
    if (*bind_addr) {
 
179
        int     aierr;
 
180
        struct addrinfo *res0;
 
181
 
 
182
        if ((aierr = hostaddr_to_sockaddr(bind_addr, (char *) 0, 0, &res0)) != 0)
 
183
            msg_fatal("%s: bad %s parameter: %s: %s",
 
184
                      myname, bind_var, bind_addr, MAI_STRERROR(aierr));
 
185
        if (bind(sock, res0->ai_addr, res0->ai_addrlen) < 0)
 
186
            msg_warn("%s: bind %s: %m", myname, bind_addr);
 
187
        else if (msg_verbose)
 
188
            msg_info("%s: bind %s", myname, bind_addr);
 
189
        freeaddrinfo(res0);
147
190
    }
148
191
 
149
192
    /*
150
193
     * When running as a virtual host, bind to the virtual interface so that
151
194
     * the mail appears to come from the "right" machine address.
 
195
     * 
 
196
     * XXX The IPv6 patch expands the null host (as client endpoint) and uses
 
197
     * the result as the loopback address list.
152
198
     */
153
 
    else if ((addr_list = own_inet_addr_list())->used == 1) {
154
 
        memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr));
155
 
        inaddr = ntohl(sin.sin_addr.s_addr);
156
 
        if (!IN_CLASSA(inaddr)
157
 
            || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
158
 
            if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
159
 
                msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
160
 
            if (msg_verbose)
161
 
                msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
 
199
    else {
 
200
        int     count = 0;
 
201
        struct sockaddr *own_addr = 0;
 
202
        INET_ADDR_LIST *addr_list = own_inet_addr_list();
 
203
        struct sockaddr_storage *s;
 
204
 
 
205
        for (s = addr_list->addrs; s < addr_list->addrs + addr_list->used; s++) {
 
206
            if (SOCK_ADDR_FAMILY(s) == sa->sa_family) {
 
207
                if (count++ > 0)
 
208
                    break;
 
209
                own_addr = SOCK_ADDR_PTR(s);
 
210
            }
 
211
        }
 
212
        if (count == 1 && !sock_addr_in_loopback(own_addr)) {
 
213
            if (bind(sock, own_addr, SOCK_ADDR_LEN(own_addr)) < 0) {
 
214
                SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr),
 
215
                                     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
 
216
                msg_warn("%s: bind %s: %m", myname, hostaddr.buf);
 
217
            } else if (msg_verbose) {
 
218
                SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr),
 
219
                                     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
 
220
                msg_info("%s: bind %s", myname, hostaddr.buf);
 
221
            }
162
222
        }
163
223
    }
164
224
 
165
225
    /*
166
226
     * Connect to the SMTP server.
167
227
     */
168
 
    sin.sin_port = port;
169
 
    memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
170
 
 
 
228
    SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
171
229
    if (msg_verbose)
172
230
        msg_info("%s: trying: %s[%s] port %d...",
173
 
                 myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
 
231
                 myname, addr->name, hostaddr.buf, ntohs(port));
174
232
    if (var_smtp_conn_tmout > 0) {
175
233
        non_blocking(sock, NON_BLOCKING);
176
 
        conn_stat = timed_connect(sock, (struct sockaddr *) & sin,
177
 
                                  sizeof(sin), var_smtp_conn_tmout);
 
234
        conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout);
178
235
        saved_errno = errno;
179
236
        non_blocking(sock, BLOCKING);
180
237
        errno = saved_errno;
181
238
    } else {
182
 
        conn_stat = sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin));
 
239
        conn_stat = sane_connect(sock, sa, salen);
183
240
    }
184
241
    if (conn_stat < 0) {
185
242
        vstring_sprintf(why, "connect to %s[%s]: %m",
186
 
                        addr->name, inet_ntoa(sin.sin_addr));
 
243
                        addr->name, hostaddr.buf);
187
244
        smtp_errno = SMTP_ERR_RETRY;
188
245
        close(sock);
189
246
        return (0);
194
251
     */
195
252
    if (read_wait(sock, var_smtp_helo_tmout) < 0) {
196
253
        vstring_sprintf(why, "connect to %s[%s]: read timeout",
197
 
                        addr->name, inet_ntoa(sin.sin_addr));
 
254
                        addr->name, hostaddr.buf);
198
255
        smtp_errno = SMTP_ERR_RETRY;
199
256
        close(sock);
200
257
        return (0);
206
263
    stream = vstream_fdopen(sock, O_RDWR);
207
264
    if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
208
265
        vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial SMTP greeting",
209
 
                        addr->name, inet_ntoa(sin.sin_addr));
 
266
                        addr->name, hostaddr.buf);
210
267
        smtp_errno = SMTP_ERR_RETRY;
211
268
        vstream_fclose(stream);
212
269
        return (0);
213
270
    }
214
271
    vstream_ungetc(stream, ch);
215
 
    return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
 
272
 
 
273
    /*
 
274
     * Skip this host if it sends a 4xx or 5xx greeting. This prevents us
 
275
     * from counting it towards the MX session limit. Unfortunately, this
 
276
     * also means that we have to salvage the server's response ourself so
 
277
     * that it can be included in logging or in non-delivery reports. It does
 
278
     * not hurt if we keep the test for a 4xx or 5xx greeting in smtp_helo().
 
279
     */
 
280
    if (ch == '4' || (ch == '5' && var_smtp_skip_5xx_greeting)) {
 
281
        VSTRING *salvage_buf = smtp_salvage(stream);
 
282
 
 
283
        vstring_sprintf(why, "connect to %s[%s]: server refused to talk to me: %s",
 
284
                        addr->name, hostaddr.buf, STR(salvage_buf));
 
285
        vstring_free(salvage_buf);
 
286
        smtp_errno = SMTP_ERR_RETRY;
 
287
        vstream_fclose(stream);
 
288
        return (0);
 
289
    }
 
290
    return (smtp_session_alloc(stream, dest, addr->name,
 
291
                               hostaddr.buf, port, sess_flags));
216
292
}
217
293
 
218
294
/* smtp_parse_destination - parse destination */
234
310
     * Parse the host/port information. We're working with a copy of the
235
311
     * destination argument so the parsing can be destructive.
236
312
     */
237
 
    if ((err = host_port(buf, hostp, &service, def_service)) != 0)
 
313
    if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
238
314
        msg_fatal("%s in SMTP server description: %s", err, destination);
239
315
 
240
316
    /*
241
317
     * Convert service to port number, network byte order.
242
318
     */
243
 
    if (alldig(service) && (port = atoi(service)) != 0) {
 
319
    if (alldig(service)) {
 
320
        if ((port = atoi(service)) >= 65536)
 
321
            msg_fatal("bad network port in destination: %s", destination);
244
322
        *portp = htons(port);
245
323
    } else {
246
324
        if ((sp = getservbyname(service, protocol)) == 0)
250
328
    return (buf);
251
329
}
252
330
 
 
331
/* smtp_cleanup_session - clean up after using a session */
 
332
 
 
333
static void smtp_cleanup_session(SMTP_STATE *state)
 
334
{
 
335
    SMTP_SESSION *session = state->session;
 
336
 
 
337
    /*
 
338
     * Inform the postmaster of trouble.
 
339
     */
 
340
    if (session->history != 0
 
341
        && (session->error_mask & name_mask(VAR_NOTIFY_CLASSES,
 
342
                                            mail_error_masks,
 
343
                                            var_notify_classes)) != 0)
 
344
        smtp_chat_notify(session);
 
345
 
 
346
    /*
 
347
     * When session caching is enabled, cache the first good session for this
 
348
     * delivery request under the next-hop destination, and cache all good
 
349
     * sessions under their server network address (destroying the session in
 
350
     * the process).
 
351
     * 
 
352
     * Caching under the next-hop destination name (rather than the fall-back
 
353
     * destination) allows us to skip over non-responding primary or backup
 
354
     * hosts. In fact, this is the only benefit of caching logical to
 
355
     * physical bindings; caching a session under its own hostname provides
 
356
     * no performance benefit, given the way smtp_connect() works.
 
357
     * 
 
358
     * XXX Should not cache TLS sessions unless we are using a single-session,
 
359
     * in-process, cache. And if we did, we should passivate VSTREAM objects
 
360
     * in addition to passivating SMTP_SESSION objects.
 
361
     * 
 
362
     * XXX Workaround. If this host spoke TLS, connection caching was already
 
363
     * turned off for this session by smtp_tls_start(). However, this alone
 
364
     * does not distinguish between "good TLS connection" and "bad
 
365
     * connection".
 
366
     * 
 
367
     * In the case of "bad connection" to a primary host we want to store the
 
368
     * first good alternate connection under the logical next-hop destination
 
369
     * name name. In the case of a good primary TLS connection that would not
 
370
     * make sense: the Postfix cache would prefer non-TLS secondary hosts
 
371
     * over TLS-enabled primary hosts!
 
372
     * 
 
373
     * The real fix is to have three-valued connection caching state: "do
 
374
     * cache", "don't cache", and "bad connection", but that involves more
 
375
     * change than is allowed in a stable release.
 
376
     * 
 
377
     * To distinguish good TLS connections from bad connections we reset the
 
378
     * logical next-hop state, so that we won't cache connections to
 
379
     * less-preferred MX hosts under the logical next-hop destination.
 
380
     */
 
381
    if (session->reuse_count > 0) {
 
382
        smtp_save_session(state);
 
383
        if (HAVE_NEXTHOP_STATE(state))
 
384
            FREE_NEXTHOP_STATE(state);
 
385
    } else {
 
386
#ifdef USE_TLS
 
387
        if (session->tls_context)
 
388
            if (HAVE_NEXTHOP_STATE(state))
 
389
                FREE_NEXTHOP_STATE(state);
 
390
#endif
 
391
        smtp_session_free(session);
 
392
    }
 
393
    state->session = 0;
 
394
 
 
395
    /*
 
396
     * Clean up the lists with todo and dropped recipients.
 
397
     */
 
398
    smtp_rcpt_cleanup(state);
 
399
}
 
400
 
 
401
/* smtp_scrub_address_list - delete all cached addresses from list */
 
402
 
 
403
static void smtp_scrub_addr_list(HTABLE *cached_addr, DNS_RR **addr_list)
 
404
{
 
405
    MAI_HOSTADDR_STR hostaddr;
 
406
    DNS_RR *addr;
 
407
    DNS_RR *next;
 
408
 
 
409
    /*
 
410
     * XXX Extend the DNS_RR structure with fields for the printable address
 
411
     * and/or binary sockaddr representations, so that we can avoid repeated
 
412
     * binary->string transformations for the same address.
 
413
     */
 
414
    for (addr = *addr_list; addr; addr = next) {
 
415
        next = addr->next;
 
416
        if (dns_rr_to_pa(addr, &hostaddr) == 0) {
 
417
            msg_warn("cannot convert type %s resource record to socket address",
 
418
                     dns_strtype(addr->type));
 
419
            continue;
 
420
        }
 
421
        if (htable_locate(cached_addr, hostaddr.buf))
 
422
            *addr_list = dns_rr_remove(*addr_list, addr);
 
423
    }
 
424
}
 
425
 
 
426
/* smtp_update_addr_list - common address list update */
 
427
 
 
428
static void smtp_update_addr_list(DNS_RR **addr_list, const char *server_addr,
 
429
                                          int session_count)
 
430
{
 
431
    DNS_RR *addr;
 
432
    DNS_RR *next;
 
433
    int     aierr;
 
434
    struct addrinfo *res0;
 
435
 
 
436
    if (*addr_list == 0)
 
437
        return;
 
438
 
 
439
    /*
 
440
     * Truncate the address list if we are not going to use it anyway.
 
441
     */
 
442
    if (session_count == var_smtp_mxsess_limit
 
443
        || session_count == var_smtp_mxaddr_limit) {
 
444
        dns_rr_free(*addr_list);
 
445
        *addr_list = 0;
 
446
        return;
 
447
    }
 
448
 
 
449
    /*
 
450
     * Convert server address to internal form, and look it up in the address
 
451
     * list.
 
452
     * 
 
453
     * XXX smtp_reuse_session() breaks if we remove two or more adjacent list
 
454
     * elements but do not truncate the list to zero length.
 
455
     * 
 
456
     * XXX Extend the SMTP_SESSION structure with sockaddr information so that
 
457
     * we can avoid repeated string->binary transformations for the same
 
458
     * address.
 
459
     */
 
460
    if ((aierr = hostaddr_to_sockaddr(server_addr, (char *) 0, 0, &res0)) != 0) {
 
461
        msg_warn("hostaddr_to_sockaddr %s: %s",
 
462
                 server_addr, MAI_STRERROR(aierr));
 
463
    } else {
 
464
        for (addr = *addr_list; addr; addr = next) {
 
465
            next = addr->next;
 
466
            if (DNS_RR_EQ_SA(addr, (struct sockaddr *) res0->ai_addr)) {
 
467
                *addr_list = dns_rr_remove(*addr_list, addr);
 
468
                break;
 
469
            }
 
470
        }
 
471
        freeaddrinfo(res0);
 
472
    }
 
473
}
 
474
 
 
475
/* smtp_reuse_session - try to use existing connection, return session count */
 
476
 
 
477
static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx,
 
478
                                      const char *domain, unsigned port,
 
479
                                   DNS_RR **addr_list, int domain_best_pref)
 
480
{
 
481
    int     session_count = 0;
 
482
    DNS_RR *addr;
 
483
    DNS_RR *next;
 
484
    int     saved_final_server = state->final_server;
 
485
    SMTP_SESSION *session;
 
486
 
 
487
    /*
 
488
     * First, search the cache by logical destination. We truncate the server
 
489
     * address list when all the sessions for this destination are used up,
 
490
     * to reduce the number of variables that need to be checked later.
 
491
     * 
 
492
     * Note: lookup by logical destination restores the "best MX" bit.
 
493
     */
 
494
    if (*addr_list && SMTP_RCPT_LEFT(state) > 0
 
495
    && (session = smtp_reuse_domain(state, lookup_mx, domain, port)) != 0) {
 
496
        session_count = 1;
 
497
        smtp_update_addr_list(addr_list, session->addr, session_count);
 
498
        state->final_server = (saved_final_server && *addr_list == 0);
 
499
        smtp_xfer(state);
 
500
        smtp_cleanup_session(state);
 
501
    }
 
502
 
 
503
    /*
 
504
     * Second, search the cache by primary MX address. Again, we use address
 
505
     * list truncation so that we have to check fewer variables later.
 
506
     * 
 
507
     * XXX This loop is safe because smtp_update_addr_list() either truncates
 
508
     * the list to zero length, or removes at most one list element.
 
509
     */
 
510
    for (addr = *addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) {
 
511
        if (addr->pref != domain_best_pref)
 
512
            break;
 
513
        next = addr->next;
 
514
        if ((session = smtp_reuse_addr(state, addr, port)) != 0) {
 
515
            session->features |= SMTP_FEATURE_BEST_MX;
 
516
            session_count += 1;
 
517
            smtp_update_addr_list(addr_list, session->addr, session_count);
 
518
            if (*addr_list == 0)
 
519
                next = 0;
 
520
            state->final_server = (saved_final_server && next == 0);
 
521
            smtp_xfer(state);
 
522
            smtp_cleanup_session(state);
 
523
        }
 
524
    }
 
525
    return (session_count);
 
526
}
 
527
 
253
528
/* smtp_connect - establish SMTP connection */
254
529
 
255
530
int     smtp_connect(SMTP_STATE *state)
257
532
    DELIVER_REQUEST *request = state->request;
258
533
    VSTRING *why = vstring_alloc(10);
259
534
    char   *dest_buf;
260
 
    char   *host;
 
535
    char   *domain;
261
536
    unsigned port;
262
 
    char   *def_service = "smtp";       /* XXX configurable? */
 
537
    char   *def_service = "smtp";       /* XXX ##IPPORT_SMTP? */
263
538
    ARGV   *sites;
264
539
    char   *dest;
265
540
    char  **cpp;
269
544
    int     addr_count;
270
545
    int     sess_count;
271
546
    int     misc_flags = SMTP_MISC_FLAG_DEFAULT;
 
547
    SMTP_SESSION *session;
 
548
    int     lookup_mx;
 
549
    unsigned domain_best_pref;
 
550
    int     sess_flags = SMTP_SESS_FLAG_NONE;
 
551
    int     i_am_mx = 0;
 
552
    int     non_fallback_sites;
272
553
 
273
554
    /*
274
555
     * First try to deliver to the indicated destination, then try to deliver
281
562
    argv_add(sites, request->nexthop, (char *) 0);
282
563
    if (sites->argc == 0)
283
564
        msg_panic("null destination: \"%s\"", request->nexthop);
 
565
    non_fallback_sites = sites->argc;
284
566
    argv_split_append(sites, var_fallback_relay, ", \t\r\n");
285
567
 
286
568
    /*
299
581
     * then is to build this into the pre-existing SMTP client without
300
582
     * getting lost in the complexity.
301
583
     */
 
584
#define IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites) \
 
585
            (*(cpp) && (cpp) >= (sites)->argv + (non_fallback_sites))
 
586
 
302
587
    for (cpp = sites->argv; SMTP_RCPT_LEFT(state) > 0 && (dest = *cpp) != 0; cpp++) {
303
 
        state->final_server = (cpp[1] == 0);
304
588
 
305
589
        /*
306
590
         * Parse the destination. Default is to use the SMTP port. Look up
307
591
         * the address instead of the mail exchanger when a quoted host is
308
592
         * specified, or when DNS lookups are disabled.
309
593
         */
310
 
        dest_buf = smtp_parse_destination(dest, def_service, &host, &port);
 
594
        dest_buf = smtp_parse_destination(dest, def_service, &domain, &port);
311
595
 
312
596
        /*
313
597
         * Resolve an SMTP server. Skip mail exchanger lookups when a quoted
314
598
         * host is specified, or when DNS lookups are disabled.
315
599
         */
316
600
        if (msg_verbose)
317
 
            msg_info("connecting to %s port %d", host, ntohs(port));
318
 
        if (ntohs(port) != 25)
 
601
            msg_info("connecting to %s port %d", domain, ntohs(port));
 
602
        if (ntohs(port) != IPPORT_SMTP)
319
603
            misc_flags &= ~SMTP_MISC_FLAG_LOOP_DETECT;
320
604
        else
321
605
            misc_flags |= SMTP_MISC_FLAG_LOOP_DETECT;
322
 
        if (var_disable_dns || *dest == '[') {
323
 
            addr_list = smtp_host_addr(host, misc_flags, why);
 
606
        lookup_mx = (var_disable_dns == 0 && *dest != '[');
 
607
        if (!lookup_mx) {
 
608
            addr_list = smtp_host_addr(domain, misc_flags, why);
 
609
            /* XXX We could be an MX host for this destination... */
324
610
        } else {
325
 
            addr_list = smtp_domain_addr(host, misc_flags, why);
326
 
        }
327
 
        myfree(dest_buf);
 
611
            addr_list = smtp_domain_addr(domain, misc_flags, why, &i_am_mx);
 
612
            /* If we're MX host, don't connect to non-MX backups. */
 
613
            if (i_am_mx)
 
614
                argv_truncate(sites, cpp - sites->argv + 1);
 
615
        }
 
616
        state->final_server = (cpp[1] == 0);
 
617
 
 
618
        /*
 
619
         * When session caching is enabled, store the first good session for
 
620
         * this delivery request under the next-hop destination name. All
 
621
         * good sessions will be stored under their specific server IP
 
622
         * address.
 
623
         * 
 
624
         * XXX Replace sites->argv by (lookup_mx, domain, port) triples so we
 
625
         * don't have to make clumsy ad-hoc copies and keep track of who
 
626
         * free()s the memory.
 
627
         * 
 
628
         * XXX smtp_session_cache_destinations specifies domain names without
 
629
         * :port, because : is already used for maptype:mapname. Because of
 
630
         * this limitation we use the bare domain without the optional [] or
 
631
         * non-default TCP port.
 
632
         * 
 
633
         * Opportunistic (a.k.a. on-demand) session caching on request by the
 
634
         * queue manager. This is turned temporarily when a destination has a
 
635
         * high volume of mail in the active queue.
 
636
         */
 
637
        if (cpp == sites->argv
 
638
            && ((var_smtp_cache_demand && (request->flags & DEL_REQ_FLAG_SCACHE) != 0)
 
639
                || (smtp_cache_dest && string_list_match(smtp_cache_dest, domain)))) {
 
640
            sess_flags |= SMTP_SESS_FLAG_CACHE;
 
641
            SET_NEXTHOP_STATE(state, lookup_mx, domain, port);
 
642
        }
328
643
 
329
644
        /*
330
645
         * Don't try any backup host if mail loops to myself. That would just
331
646
         * make the problem worse.
332
647
         */
333
 
        if (addr_list == 0 && smtp_errno == SMTP_ERR_LOOP)
 
648
        if (addr_list == 0 && smtp_errno == SMTP_ERR_LOOP) {
 
649
            myfree(dest_buf);
334
650
            break;
 
651
        }
 
652
 
 
653
        /*
 
654
         * No early loop exit or we have a memory leak with dest_buf.
 
655
         */
 
656
        if (addr_list)
 
657
            domain_best_pref = addr_list->pref;
 
658
 
 
659
        /*
 
660
         * Delete visited cached hosts from the address list.
 
661
         * 
 
662
         * Optionally search the connection cache by domain name or by primary
 
663
         * MX address.
 
664
         * 
 
665
         * Enforce the MX session and MX address counts per next-hop or
 
666
         * fall-back destination. smtp_reuse_session() will truncate the
 
667
         * address list when either limit is reached.
 
668
         */
 
669
        if (addr_list && (sess_flags & SMTP_SESS_FLAG_CACHE) != 0) {
 
670
            if (state->cache_used->used > 0)
 
671
                smtp_scrub_addr_list(state->cache_used, &addr_list);
 
672
            sess_count = addr_count =
 
673
                smtp_reuse_session(state, lookup_mx, domain, port,
 
674
                                   &addr_list, domain_best_pref);
 
675
        } else
 
676
            sess_count = addr_count = 0;
335
677
 
336
678
        /*
337
679
         * Connect to an SMTP server.
342
684
         * the end of an SMTP session, weed out the recipient list. Unmark
343
685
         * any left-over recipients and try to deliver them to a backup mail
344
686
         * server.
 
687
         * 
 
688
         * Cache the first good session under the next-hop destination name.
 
689
         * Cache all good sessions under their physical endpoint.
 
690
         * 
 
691
         * Don't query the session cache for primary MX hosts. We already did
 
692
         * that in smtp_reuse_session(), and if any were found in the cache,
 
693
         * they were already deleted from the address list.
345
694
         */
346
 
        sess_count = addr_count = 0;
347
695
        for (addr = addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) {
348
696
            next = addr->next;
349
697
            if (++addr_count == var_smtp_mxaddr_limit)
350
698
                next = 0;
351
 
            if ((state->session = smtp_connect_addr(addr, port, why)) != 0) {
352
 
                state->features = 0;            /* XXX should be SESSION info */
 
699
            if ((sess_flags & SMTP_SESS_FLAG_CACHE) == 0
 
700
                || addr->pref == domain_best_pref
 
701
                || (session = smtp_reuse_addr(state, addr, port)) == 0)
 
702
                session = smtp_connect_addr(dest, addr, port, why, sess_flags);
 
703
            if ((state->session = session) != 0) {
353
704
                if (++sess_count == var_smtp_mxsess_limit)
354
705
                    next = 0;
355
706
                state->final_server = (cpp[1] == 0 && next == 0);
356
 
                state->session->best = (addr->pref == addr_list->pref);
357
 
                debug_peer_check(state->session->host, state->session->addr);
358
 
                if (smtp_helo(state, misc_flags) == 0)
 
707
                if (addr->pref == domain_best_pref)
 
708
                    session->features |= SMTP_FEATURE_BEST_MX;
 
709
                if ((session->features & SMTP_FEATURE_FROM_CACHE) == 0
 
710
                    && smtp_helo(state, misc_flags) != 0) {
 
711
                    if (vstream_ferror(session->stream) == 0
 
712
                        && vstream_feof(session->stream) == 0)
 
713
                        smtp_quit(state);
 
714
                } else
359
715
                    smtp_xfer(state);
360
 
                if (state->history != 0) {
361
 
                    if (state->error_mask & name_mask(VAR_NOTIFY_CLASSES,
362
 
                                      mail_error_masks, var_notify_classes))
363
 
                        smtp_chat_notify(state);
364
 
                    smtp_chat_reset(state);
365
 
                }
366
 
                state->error_mask = 0;
367
 
                state->size_limit = 0;
368
 
                /* XXX smtp_xfer() may abort in the middle of DATA. */
369
 
                smtp_session_free(state->session);
370
 
                state->session = 0;
371
 
#ifdef USE_SASL_AUTH
372
 
                smtp_sasl_cleanup(state);
373
 
#endif
374
 
                debug_peer_restore();
375
 
                smtp_rcpt_cleanup(state);
 
716
                smtp_cleanup_session(state);
376
717
            } else {
377
718
                msg_info("%s (port %d)", vstring_str(why), ntohs(port));
378
719
            }
379
720
        }
380
721
        dns_rr_free(addr_list);
 
722
        myfree(dest_buf);
381
723
    }
382
724
 
383
725
    /*
386
728
     * 
387
729
     * Pay attention to what could be configuration problems, and pretend that
388
730
     * these are recoverable rather than bouncing the mail.
 
731
     * 
 
732
     * In case of a "no error" indication we make up an excuse; this can happen
 
733
     * when the fall-back relay was already tried via a cached connection, so
 
734
     * that the address list scrubber left behind an empty list.
389
735
     */
390
736
    if (SMTP_RCPT_LEFT(state) > 0) {
 
737
        if (smtp_errno == SMTP_ERR_NONE) {
 
738
            vstring_sprintf(why, "server unavailable or unable to receive mail");
 
739
            smtp_errno = SMTP_ERR_RETRY;
 
740
        }
391
741
        switch (smtp_errno) {
392
742
 
393
743
        default:
400
750
             * The fall-back destination did not resolve as expected, or it
401
751
             * is refusing to talk to us, or mail for it loops back to us.
402
752
             */
403
 
            if (sites->argc > 1 && cpp > sites->argv) {
 
753
            if (IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites)) {
404
754
                msg_warn("%s configuration problem", VAR_FALLBACK_RELAY);
405
755
                smtp_errno = SMTP_ERR_RETRY;
406
756
            }
449
799
    /*
450
800
     * Cleanup.
451
801
     */
 
802
    if (HAVE_NEXTHOP_STATE(state))
 
803
        FREE_NEXTHOP_STATE(state);
452
804
    argv_free(sites);
453
805
    vstring_free(why);
454
806
    return (state->status);