@@ -25,6 +25,7 @@ type message struct {
2525 RcptOpts []* smtp.RcptOptions
2626 Data []byte
2727 Opts * smtp.MailOptions
28+ XForward map [string ]string
2829}
2930
3031type backend struct {
@@ -98,7 +99,9 @@ func (s *session) Auth(mech string) (sasl.Server, error) {
9899}
99100
100101func (s * session ) Reset () {
101- s .msg = & message {}
102+ s .msg = & message {
103+ XForward : make (map [string ]string ),
104+ }
102105}
103106
104107func (s * session ) Logout () error {
@@ -157,6 +160,11 @@ func (s *session) Data(r io.Reader) error {
157160 return nil
158161}
159162
163+ func (s * session ) XForward (attrName , attrValue string ) error {
164+ s .msg .XForward [attrName ] = attrValue
165+ return nil
166+ }
167+
160168func (s * session ) LMTPData (r io.Reader , collector smtp.StatusCollector ) error {
161169 if err := s .Data (r ); err != nil {
162170 return err
@@ -1712,3 +1720,90 @@ func TestServerMTPRIORITY(t *testing.T) {
17121720 t .Fatal ("Incorrect MtPriority parameter value:" , fmt .Sprintf ("expected %d, got %d" , expectedPriority , * priority ))
17131721 }
17141722}
1723+
1724+ func TestServerXFORWARD (t * testing.T ) {
1725+ be , s , c , scanner , caps := testServerEhlo (t ,
1726+ func (s * smtp.Server ) {
1727+ s .EnableXFORWARD = true
1728+ })
1729+ defer s .Close ()
1730+ defer c .Close ()
1731+
1732+ if _ , ok := caps ["XFORWARD NAME ADDR PROTO HELO" ]; ! ok {
1733+ t .Fatal ("Missing capability: XFORWARD" )
1734+ }
1735+
1736+ io .WriteString (c , "MAIL FROM:<root@nsa.gov>\r \n " )
1737+ scanner .Scan ()
1738+ if ! strings .HasPrefix (scanner .Text (), "250 " ) {
1739+ t .Fatal ("Invalid MAIL response:" , scanner .Text ())
1740+ }
1741+
1742+ io .WriteString (c , "RCPT TO:<root@gchq.gov.uk>\r \n " )
1743+ scanner .Scan ()
1744+ if ! strings .HasPrefix (scanner .Text (), "250 " ) {
1745+ t .Fatal ("Invalid RCPT response:" , scanner .Text ())
1746+ }
1747+
1748+ // Atrribute names are case insensitive, check we normalised them
1749+ io .WriteString (c , "XFORWARD NAME=spike.porcupine.org ADDR=168.100.189.2 proto=ESMTP\r \n " )
1750+ scanner .Scan ()
1751+ if ! strings .HasPrefix (scanner .Text (), "250 " ) {
1752+ t .Fatal ("Invalid XFORWARD response:" , scanner .Text ())
1753+ }
1754+
1755+ io .WriteString (c , "DATA\r \n " )
1756+ scanner .Scan ()
1757+ if ! strings .HasPrefix (scanner .Text (), "354 " ) {
1758+ t .Fatal ("Invalid DATA response:" , scanner .Text ())
1759+ }
1760+
1761+ io .WriteString (c , "From: root@nsa.gov\r \n " )
1762+ io .WriteString (c , "\r \n " )
1763+ io .WriteString (c , "Hey\r <3\r \n " )
1764+ io .WriteString (c , "..this dot is fine\r \n " )
1765+ io .WriteString (c , ".\r \n " )
1766+ scanner .Scan ()
1767+ if ! strings .HasPrefix (scanner .Text (), "250 " ) {
1768+ t .Fatal ("Invalid DATA response:" , scanner .Text ())
1769+ }
1770+
1771+ if len (be .messages ) != 0 || len (be .anonmsgs ) != 1 {
1772+ t .Fatal ("Invalid number of sent messages:" , be .messages , be .anonmsgs )
1773+ }
1774+
1775+ msg := be .anonmsgs [0 ]
1776+
1777+ if len (msg .XForward ) != 3 {
1778+ t .Fatal ("Invalid XFORWARD data:" , msg .XForward )
1779+ }
1780+
1781+ if got , ok := msg .XForward ["NAME" ]; ! ok {
1782+ t .Fatal ("Missing XFORWARD attribute NAME" )
1783+ } else if got != "spike.porcupine.org" {
1784+ t .Fatal ("Invalid XFORWARD attribute value for NAME" , got )
1785+ }
1786+
1787+ if got , ok := msg .XForward ["ADDR" ]; ! ok {
1788+ t .Fatal ("Missing XFORWARD attribute ADDR" )
1789+ } else if got != "168.100.189.2" {
1790+ t .Fatal ("Invalid XFORWARD attribute value for ADDR" , got )
1791+ }
1792+
1793+ if got , ok := msg .XForward ["PROTO" ]; ! ok {
1794+ t .Fatal ("Missing (normalised) XFORWARD attribute PROTO" )
1795+ } else if got != "ESMTP" {
1796+ t .Fatal ("Invalid (normalised) XFORWARD attribute value for PROTO" , got )
1797+ }
1798+
1799+ // Sanity that the rest of the connection continued fine
1800+ if msg .From != "root@nsa.gov" {
1801+ t .Fatal ("Invalid mail sender:" , msg .From )
1802+ }
1803+ if len (msg .To ) != 1 || msg .To [0 ] != "root@gchq.gov.uk" {
1804+ t .Fatal ("Invalid mail recipients:" , msg .To )
1805+ }
1806+ if string (msg .Data ) != "From: root@nsa.gov\r \n \r \n Hey\r <3\r \n .this dot is fine\r \n " {
1807+ t .Fatal ("Invalid mail data:" , string (msg .Data ))
1808+ }
1809+ }
0 commit comments