X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fsmtp_out.c;h=6fd0bf72909d3a659d543d6f4d2016a739f04799;hb=7ea1237c783e380d7bdb86c90b13d8203c7ecf26;hp=9221aa8680dd5985987574abf0d84424dbf7671d;hpb=0ab63f3dea522591218c0d65c78a686b7fa64db6;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c index 9221aa868..6fd0bf729 100644 --- a/src/src/smtp_out.c +++ b/src/src/smtp_out.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2016 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* A number of functions for driving outgoing SMTP calls. */ @@ -45,7 +45,7 @@ if (!istring) return TRUE; if (!(expint = expand_string(istring))) { - if (expand_string_forcedfail) return TRUE; + if (f.expand_string_forcedfail) return TRUE; addr->transport_return = PANIC; addr->message = string_sprintf("failed to expand \"interface\" " "option for %s: %s", msg, expand_string_message); @@ -150,14 +150,44 @@ socklen_t len = sizeof(tinfo); if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0) { - /* This is a somewhat dubious detection method; totally undocumented so likely - to fail in future kernels. There seems to be no documented way. */ - - if (tinfo.tcpi_unacked > 1) + switch (tcp_out_fastopen) { - DEBUG(D_transport|D_v) debug_printf("TCP_FASTOPEN mode connection\n"); - tcp_out_fastopen = TRUE; + /* This is a somewhat dubious detection method; totally undocumented so likely + to fail in future kernels. There seems to be no documented way. What we really + want to know is if the server sent smtp-banner data before our ACK of his SYN,ACK + hit him. What this (possibly?) detects is whether we sent a TFO cookie with our + SYN, as distinct from a TFO request. This gets a false-positive when the server + key is rotated; we send the old one (which this test sees) but the server returns + the new one and does not send its SMTP banner before we ACK his SYN,ACK. + To force that rotation case: + '# echo -n "00000000-00000000-00000000-0000000" >/proc/sys/net/ipv4/tcp_fastopen_key' + The kernel seems to be counting unack'd packets. */ + + case 1: + if (tinfo.tcpi_unacked > 1) + { + DEBUG(D_transport|D_v) + debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.tcpi_unacked); + tcp_out_fastopen = 2; + } + break; + +#ifdef notdef /* This seems to always fire, meaning that we cannot tell + whether the server accepted data we sent. For now assume + that it did. */ + + /* If there was data-on-SYN but we had to retrasnmit it, declare no TFO */ + + case 2: + if (!(tinfo.tcpi_options & TCPI_OPT_SYN_DATA)) + { + DEBUG(D_transport|D_v) debug_printf("TFO: had to retransmit\n"); + tcp_out_fastopen = 0; + } + break; +#endif } + } # endif } @@ -182,6 +212,8 @@ int dscp_level; int dscp_option; int sock; int save_errno = 0; +const blob * fastopen_blob = NULL; + #ifndef DISABLE_EVENT deliver_host_address = host->address; @@ -231,16 +263,14 @@ requested some early-data then include that in the TFO request. */ else { - const blob * fastopen = NULL; - #ifdef TCP_FASTOPEN if (verify_check_given_host(&ob->hosts_try_fastopen, host) == OK) - fastopen = early_data ? early_data : &tcp_fastopen_nodata; + fastopen_blob = early_data ? early_data : &tcp_fastopen_nodata; #endif - if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0) + if (ip_connect(sock, host_af, host->address, port, timeout, fastopen_blob) < 0) save_errno = errno; - else if (early_data && !fastopen && early_data->data && early_data->len) + else if (early_data && !fastopen_blob && early_data->data && early_data->len) if (send(sock, early_data->data, early_data->len, 0) < 0) save_errno = errno; } @@ -279,7 +309,7 @@ else } if (ob->keepalive) ip_keepalive(sock, host->address, TRUE); #ifdef TCP_FASTOPEN - tfo_out_check(sock); + if (fastopen_blob) tfo_out_check(sock); #endif return sock; } @@ -381,11 +411,11 @@ HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, more ? " (more expected)" : ""); #ifdef SUPPORT_TLS -if (tls_out.active == outblock->sock) - rc = tls_write(FALSE, outblock->buffer, n, more); +if (outblock->cctx->tls_ctx) + rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more); else #endif - rc = send(outblock->sock, outblock->buffer, n, + rc = send(outblock->cctx->sock, outblock->buffer, n, #ifdef MSG_MORE more ? MSG_MORE : 0 #else @@ -414,7 +444,7 @@ return TRUE; any error message. Arguments: - outblock contains buffer for pipelining, and socket + sx SMTP connection, contains buffer for pipelining, and socket mode buffer, write-with-more-likely, write format a format, starting with one of of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT. @@ -427,8 +457,9 @@ Returns: 0 if command added to pipelining buffer, with nothing transmitted */ int -smtp_write_command(smtp_outblock * outblock, int mode, const char *format, ...) +smtp_write_command(void * sx, int mode, const char *format, ...) { +smtp_outblock * outblock = &((smtp_context *)sx)->outblock; int count; int rc = 0; va_list ap; @@ -516,7 +547,7 @@ read_response_line(smtp_inblock *inblock, uschar *buffer, int size, int timeout) uschar *p = buffer; uschar *ptr = inblock->ptr; uschar *ptrend = inblock->ptrend; -int sock = inblock->sock; +client_conn_ctx * cctx = inblock->cctx; /* Loop for reading multiple packets or reading another packet after emptying a previously-read one. */ @@ -554,7 +585,7 @@ for (;;) /* Need to read a new input packet. */ - if((rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout)) <= 0) + if((rc = ip_recv(cctx, inblock->buffer, inblock->buffersize, timeout)) <= 0) { DEBUG(D_deliver|D_transport|D_acl) debug_printf_indent(errno ? " SMTP(%s)<<\n" : " SMTP(closed)<<\n", @@ -593,7 +624,8 @@ also returned after a reading error. In this case buffer[0] will be zero, and the error code will be in errno. Arguments: - inblock the SMTP input block (contains holding buffer, socket, etc.) + sx the SMTP connection (contains input block with holding buffer, + socket, etc.) buffer where to put the response size the size of the buffer okdigit the expected first digit of the response @@ -603,9 +635,10 @@ Returns: TRUE if a valid, non-error response was received; else FALSE */ BOOL -smtp_read_response(smtp_inblock *inblock, uschar *buffer, int size, int okdigit, +smtp_read_response(void * sx, uschar *buffer, int size, int okdigit, int timeout) { +smtp_inblock * inblock = &((smtp_context *)sx)->inblock; uschar *ptr = buffer; int count;