From 0cbd1b1d89f12a512124a88b955cc5e682eba8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Mon, 22 Mar 2021 10:41:44 +0500 Subject: [PATCH 1/7] Fix bDatHandle. Remove use limitReader on handle read binaryMime bytes --- conn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conn.go b/conn.go index b847057..e17f6d3 100644 --- a/conn.go +++ b/conn.go @@ -739,7 +739,7 @@ func (c *Conn) handleBdat(arg string) { }() } - chunk := io.LimitReader(c.text.R, int64(size)) + chunk := io.LimitReader(c.conn, int64(size)) _, err = io.Copy(c.bdatPipe, chunk) if err != nil { // Backend might return an error early using CloseWithError without consuming From 3c721647cb2c5d94a3aee519ddbf2f6847123089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Mon, 22 Mar 2021 13:55:56 +0500 Subject: [PATCH 2/7] Disable lineLimitReader when use handle BDAT data --- conn.go | 14 +++++++++----- lengthlimit_reader.go | 9 +++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/conn.go b/conn.go index e17f6d3..662cb80 100644 --- a/conn.go +++ b/conn.go @@ -40,6 +40,7 @@ type Conn struct { locker sync.Mutex binarymime bool + bdatReader *lineLimitReader bdatPipe *io.PipeWriter bdatStatus *statusCollector // used for BDAT on LMTP dataResult chan error @@ -60,15 +61,17 @@ func newConn(c net.Conn, s *Server) *Conn { } func (c *Conn) init() { + c.bdatReader = &lineLimitReader{ + R: c.conn, + LineLimit: c.server.MaxLineLength, + DisableCheck: false, + } rwc := struct { io.Reader io.Writer io.Closer }{ - Reader: &lineLimitReader{ - R: c.conn, - LineLimit: c.server.MaxLineLength, - }, + Reader: c.bdatReader, Writer: c.conn, Closer: c.conn, } @@ -739,7 +742,8 @@ func (c *Conn) handleBdat(arg string) { }() } - chunk := io.LimitReader(c.conn, int64(size)) + c.bdatReader.DisableCheck = true + chunk := io.LimitReader(c.text.R, int64(size)) _, err = io.Copy(c.bdatPipe, chunk) if err != nil { // Backend might return an error early using CloseWithError without consuming diff --git a/lengthlimit_reader.go b/lengthlimit_reader.go index d35d92c..a9a32b8 100644 --- a/lengthlimit_reader.go +++ b/lengthlimit_reader.go @@ -12,14 +12,15 @@ var ErrTooLongLine = errors.New("smtp: too longer line in input stream") // // If line length exceeds the limit - Read returns ErrTooLongLine type lineLimitReader struct { - R io.Reader - LineLimit int + R io.Reader + LineLimit int + DisableCheck bool curLineLength int } func (r *lineLimitReader) Read(b []byte) (int, error) { - if r.curLineLength > r.LineLimit { + if r.curLineLength > r.LineLimit && !r.DisableCheck { return 0, ErrTooLongLine } @@ -28,7 +29,7 @@ func (r *lineLimitReader) Read(b []byte) (int, error) { return n, err } - if r.LineLimit == 0 { + if r.LineLimit == 0 || r.DisableCheck { return n, nil } From a5f341b43992b55b7868682b08a742a4ee76d391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Mon, 22 Mar 2021 15:15:50 +0500 Subject: [PATCH 3/7] Rework lenghtlimit_reader --- conn.go | 25 ++++++++++++++----------- lengthlimit_reader.go | 9 ++++----- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/conn.go b/conn.go index 662cb80..5b5ff5c 100644 --- a/conn.go +++ b/conn.go @@ -40,11 +40,11 @@ type Conn struct { locker sync.Mutex binarymime bool - bdatReader *lineLimitReader - bdatPipe *io.PipeWriter - bdatStatus *statusCollector // used for BDAT on LMTP - dataResult chan error - bytesReceived int // counts total size of chunks when BDAT is used + lineLimitReader *lineLimitReader + bdatPipe *io.PipeWriter + bdatStatus *statusCollector // used for BDAT on LMTP + dataResult chan error + bytesReceived int // counts total size of chunks when BDAT is used fromReceived bool recipients []string @@ -61,17 +61,16 @@ func newConn(c net.Conn, s *Server) *Conn { } func (c *Conn) init() { - c.bdatReader = &lineLimitReader{ - R: c.conn, - LineLimit: c.server.MaxLineLength, - DisableCheck: false, + c.lineLimitReader = &lineLimitReader{ + R: c.conn, + LineLimit: c.server.MaxLineLength, } rwc := struct { io.Reader io.Writer io.Closer }{ - Reader: c.bdatReader, + Reader: c.lineLimitReader, Writer: c.conn, Closer: c.conn, } @@ -742,7 +741,8 @@ func (c *Conn) handleBdat(arg string) { }() } - c.bdatReader.DisableCheck = true + prevLineLimit := c.lineLimitReader.LineLimit + c.lineLimitReader.LineLimit = 0 chunk := io.LimitReader(c.text.R, int64(size)) _, err = io.Copy(c.bdatPipe, chunk) if err != nil { @@ -757,6 +757,7 @@ func (c *Conn) handleBdat(arg string) { } c.reset() + c.lineLimitReader.LineLimit = prevLineLimit return } @@ -779,6 +780,7 @@ func (c *Conn) handleBdat(arg string) { if err == errPanic { c.Close() + c.lineLimitReader.LineLimit = prevLineLimit return } @@ -786,6 +788,7 @@ func (c *Conn) handleBdat(arg string) { } else { c.WriteResponse(250, EnhancedCode{2, 0, 0}, "Continue") } + c.lineLimitReader.LineLimit = prevLineLimit } // ErrDataReset is returned by Reader pased to Data function if client does not diff --git a/lengthlimit_reader.go b/lengthlimit_reader.go index a9a32b8..695bc76 100644 --- a/lengthlimit_reader.go +++ b/lengthlimit_reader.go @@ -12,15 +12,14 @@ var ErrTooLongLine = errors.New("smtp: too longer line in input stream") // // If line length exceeds the limit - Read returns ErrTooLongLine type lineLimitReader struct { - R io.Reader - LineLimit int - DisableCheck bool + R io.Reader + LineLimit int curLineLength int } func (r *lineLimitReader) Read(b []byte) (int, error) { - if r.curLineLength > r.LineLimit && !r.DisableCheck { + if r.curLineLength > r.LineLimit && r.LineLimit > 0 { return 0, ErrTooLongLine } @@ -29,7 +28,7 @@ func (r *lineLimitReader) Read(b []byte) (int, error) { return n, err } - if r.LineLimit == 0 || r.DisableCheck { + if r.LineLimit == 0 { return n, nil } From 833db20b626ceddf1f3662446c1c58fe298e5a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Tue, 23 Mar 2021 13:31:07 +0500 Subject: [PATCH 4/7] Correct defer for handleBdat --- conn.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/conn.go b/conn.go index 5b5ff5c..6583f88 100644 --- a/conn.go +++ b/conn.go @@ -743,6 +743,10 @@ func (c *Conn) handleBdat(arg string) { prevLineLimit := c.lineLimitReader.LineLimit c.lineLimitReader.LineLimit = 0 + recover := func() { + c.lineLimitReader.LineLimit = prevLineLimit + } + defer recover() chunk := io.LimitReader(c.text.R, int64(size)) _, err = io.Copy(c.bdatPipe, chunk) if err != nil { @@ -757,7 +761,6 @@ func (c *Conn) handleBdat(arg string) { } c.reset() - c.lineLimitReader.LineLimit = prevLineLimit return } @@ -780,7 +783,6 @@ func (c *Conn) handleBdat(arg string) { if err == errPanic { c.Close() - c.lineLimitReader.LineLimit = prevLineLimit return } @@ -788,7 +790,6 @@ func (c *Conn) handleBdat(arg string) { } else { c.WriteResponse(250, EnhancedCode{2, 0, 0}, "Continue") } - c.lineLimitReader.LineLimit = prevLineLimit } // ErrDataReset is returned by Reader pased to Data function if client does not From ecc2877499144ac8a18cadaddb2a791a6874138a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Tue, 23 Mar 2021 13:38:33 +0500 Subject: [PATCH 5/7] Fix name of defer function --- conn.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conn.go b/conn.go index 6583f88..0a14a14 100644 --- a/conn.go +++ b/conn.go @@ -743,10 +743,10 @@ func (c *Conn) handleBdat(arg string) { prevLineLimit := c.lineLimitReader.LineLimit c.lineLimitReader.LineLimit = 0 - recover := func() { + recoverLineLimit := func() { c.lineLimitReader.LineLimit = prevLineLimit } - defer recover() + defer recoverLineLimit() chunk := io.LimitReader(c.text.R, int64(size)) _, err = io.Copy(c.bdatPipe, chunk) if err != nil { From 4569335bbd2143c982ceb4beffe4b5c6bd99a21c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Wed, 24 Mar 2021 15:25:41 +0500 Subject: [PATCH 6/7] Fix recover LineLimit --- conn.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/conn.go b/conn.go index 0a14a14..6b0e7b2 100644 --- a/conn.go +++ b/conn.go @@ -741,12 +741,8 @@ func (c *Conn) handleBdat(arg string) { }() } - prevLineLimit := c.lineLimitReader.LineLimit c.lineLimitReader.LineLimit = 0 - recoverLineLimit := func() { - c.lineLimitReader.LineLimit = prevLineLimit - } - defer recoverLineLimit() + chunk := io.LimitReader(c.text.R, int64(size)) _, err = io.Copy(c.bdatPipe, chunk) if err != nil { @@ -767,6 +763,8 @@ func (c *Conn) handleBdat(arg string) { c.bytesReceived += int(size) if last { + c.lineLimitReader.LineLimit = c.server.MaxLineLength + c.bdatPipe.Close() err := <-c.dataResult From e99880000c00a0b35598aa92b40e64dc91e7e6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A8=D0=B8=D0=BF=D0=B8=D1=86=D1=8B=D0=BD=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D0=BB=D0=B8=D0=B9?= Date: Wed, 24 Mar 2021 16:11:24 +0500 Subject: [PATCH 7/7] Add recover lineLimit on copy error --- conn.go | 1 + 1 file changed, 1 insertion(+) diff --git a/conn.go b/conn.go index 6b0e7b2..5296c1f 100644 --- a/conn.go +++ b/conn.go @@ -757,6 +757,7 @@ func (c *Conn) handleBdat(arg string) { } c.reset() + c.lineLimitReader.LineLimit = c.server.MaxLineLength return }