Bug: dot-stuffing may not work under some circumstances.
Damian
amavis at arcsin.de
Fri Oct 28 14:42:45 CEST 2016
Hello,
I recently hit on a bug where a "\r\n." in a mail triggered an "end of
DATA" at the upstream mail server.
>From the current (2.11) amavis source:
> #package Amavis::Out::SMTP;
> sub mail_via_smtp(@) {
> ...
> while (($nbytes = $msg->read($buff,3*16384)) > 0) {
> $smtp_handle->datasend($buff);
> }
> ...
> }
>
>
> #package Amavis::Out::SMTP::Protocol;
> sub datasend {
> my $self = shift;
> my $buff = @_ == 1 ? $_[0] : join('', at _);
> ...
> # CR/LF are never split across a buffer boundary
> $buff =~ s{\n}{\015\012}gs; # quite fast, but still a bottleneck
> if ($self->{dotstuffing}) {
> $buff =~ s{\015\012\.}{\015\012..}gs; # dot stuffing
> $self->{io}->print('.') if substr($buff,0,1) eq '.' &&
> $self->{at_line_boundary};
> }
> $self->{io}->print($buff);
> $self->{at_line_boundary} = $self->{io}->at_line_boundary;
> ...
> }
>
>
> #package Amavis::IO::RW;
> sub print {
> my $self = shift;
> $self->{out} .= $_ for @_;
> # $self->out_buff_large ? $self->flush : 1;
> length $self->{out} > 40000 ? $self->flush : 1; # inlined
> out_buff_large()
> }
>
> sub at_line_boundary {
> my $self = $_[0];
> my $eol_str = $self->{eol_str};
> my $eol_str_l = !defined($eol_str) ? 0 : length($eol_str);
> !$eol_str_l ? 1
> : substr($self->{out}, -$eol_str_l, $eol_str_l) eq $eol_str ? 1 : 0;
> }
Lets say we have a mail with a list of chunks read by mail_via_smtp()
and given to datasend():
- "40000+ chars with \r\n at the end\r\n"
-- No dot stuffing of trailing "\r\n", as there is no dot.
-- flushing of $self->{out} in Amavis::IO::RW::print().
-- Amavis::IO::RW::at_line_boundary() returns 0 in datasend(), as the
buffer is empty.
- ". some chars with dot at first position"
-- No dot stuffing via regex, as there is no leading "\r\n".
-- No dot stuffing via print('.'), as at_line_boundary is false from the
previous chunk.
I would kindly ask for a bugfix.
Thanks
Damian
More information about the amavis-users
mailing list