|
@@ -222,7 +222,7 @@ func TestTLSConfig(t *testing.T) {
|
|
|
Protocols: []string{"tls1.0", "tls1.2"},
|
|
|
},
|
|
|
})
|
|
|
- if err := s.configureSSL(); err != nil {
|
|
|
+ if err := s.configureTLS(); err != nil {
|
|
|
t.Error(err)
|
|
|
}
|
|
|
|
|
@@ -302,6 +302,550 @@ func TestHandleClient(t *testing.T) {
|
|
|
wg.Wait() // wait for handleClient to exit
|
|
|
}
|
|
|
|
|
|
+func TestGithubIssue197(t *testing.T) {
|
|
|
+ var mainlog log.Logger
|
|
|
+ var logOpenError error
|
|
|
+ defer cleanTestArtifacts(t)
|
|
|
+ sc := getMockServerConfig()
|
|
|
+ mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
|
|
|
+ if logOpenError != nil {
|
|
|
+ mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
|
|
|
+ }
|
|
|
+ conn, server := getMockServerConn(sc, t)
|
|
|
+ server.backend().Start()
|
|
|
+ // we assume that 1.1.1.1 is a domain (ip-literal syntax is incorrect)
|
|
|
+ // [2001:DB8::FF00:42:8329] is an address literal
|
|
|
+ server.setAllowedHosts([]string{"1.1.1.1", "[2001:DB8::FF00:42:8329]"})
|
|
|
+
|
|
|
+ client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(1)
|
|
|
+ go func() {
|
|
|
+ server.handleClient(client)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+ // Wait for the greeting from the server
|
|
|
+ r := textproto.NewReader(bufio.NewReader(conn.Client))
|
|
|
+ line, _ := r.ReadLine()
|
|
|
+ // fmt.Println(line)
|
|
|
+ w := textproto.NewWriter(bufio.NewWriter(conn.Client))
|
|
|
+ if err := w.PrintfLine("HELO test.test.com"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // Case 1
|
|
|
+ if err := w.PrintfLine("rcpt to: <hi@[1.1.1.1]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if client.parser.IP == nil {
|
|
|
+ t.Error("[1.1.1.1] not parsed as address-liteal")
|
|
|
+ }
|
|
|
+
|
|
|
+ // case 2, should be parsed as domain
|
|
|
+ if err := w.PrintfLine("rcpt to: <[email protected]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if client.parser.IP != nil {
|
|
|
+ t.Error("1.1.1.1 should not be parsed as an IP (syntax requires IP addresses to be in braces, eg <hi@[1.1.1.1]>")
|
|
|
+ }
|
|
|
+
|
|
|
+ // case 3
|
|
|
+ // prefix ipv6 is case insensitive
|
|
|
+ if err := w.PrintfLine("rcpt to: <hi@[ipv6:2001:DB8::FF00:42:8329]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if client.parser.IP == nil {
|
|
|
+ t.Error("[ipv6:2001:DB8::FF00:42:8329] should be parsed as an address-literal, it wasnt")
|
|
|
+ }
|
|
|
+
|
|
|
+ // case 4
|
|
|
+ if err := w.PrintfLine("rcpt to: <hi@[IPv6:2001:0db8:0000:0000:0000:ff00:0042:8329]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if client.parser.Domain != "2001:DB8::FF00:42:8329" && client.parser.IP == nil {
|
|
|
+ t.Error("[IPv6:2001:0db8:0000:0000:0000:ff00:0042:8329] is same as 2001:DB8::FF00:42:8329, lol")
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("QUIT"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ //fmt.Println("line is:", line)
|
|
|
+ expected := "221 2.0.0 Bye"
|
|
|
+ if strings.Index(line, expected) != 0 {
|
|
|
+ t.Error("expected", expected, "but got:", line)
|
|
|
+ }
|
|
|
+ wg.Wait() // wait for handleClient to exit
|
|
|
+}
|
|
|
+
|
|
|
+var githubIssue198data string
|
|
|
+
|
|
|
+var customBackend = func() backends.Decorator {
|
|
|
+ return func(p backends.Processor) backends.Processor {
|
|
|
+ return backends.ProcessWith(
|
|
|
+ func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
|
|
|
+ if task == backends.TaskSaveMail {
|
|
|
+ githubIssue198data = e.DeliveryHeader + e.Data.String()
|
|
|
+ }
|
|
|
+ return p.Process(e, task)
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// TestGithubIssue198 is an interesting test because it shows how to do an integration test for
|
|
|
+// a backend using a custom backend.
|
|
|
+func TestGithubIssue198(t *testing.T) {
|
|
|
+ var mainlog log.Logger
|
|
|
+ var logOpenError error
|
|
|
+ defer cleanTestArtifacts(t)
|
|
|
+ sc := getMockServerConfig()
|
|
|
+ mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
|
|
|
+
|
|
|
+ backends.Svc.AddProcessor("custom", customBackend)
|
|
|
+
|
|
|
+ if logOpenError != nil {
|
|
|
+ mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
|
|
|
+ }
|
|
|
+ conn, server := getMockServerConn(sc, t)
|
|
|
+ be, err := backends.New(map[string]interface{}{
|
|
|
+ "save_process": "HeadersParser|Header|custom", "primary_mail_host": "example.com"},
|
|
|
+ mainlog)
|
|
|
+ if err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ server.setBackend(be)
|
|
|
+ if err := server.backend().Start(); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ server.setAllowedHosts([]string{"1.1.1.1", "[2001:DB8::FF00:42:8329]"})
|
|
|
+
|
|
|
+ client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
|
|
|
+ client.RemoteIP = "127.0.0.1"
|
|
|
+
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(1)
|
|
|
+ go func() {
|
|
|
+ server.handleClient(client)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+ // Wait for the greeting from the server
|
|
|
+ r := textproto.NewReader(bufio.NewReader(conn.Client))
|
|
|
+ line, _ := r.ReadLine()
|
|
|
+
|
|
|
+ w := textproto.NewWriter(bufio.NewWriter(conn.Client))
|
|
|
+ // Test with HELO greeting
|
|
|
+ line = sendMessage("HELO", true, w, t, line, r, err, client)
|
|
|
+ if !strings.Contains(githubIssue198data, " SMTPS ") {
|
|
|
+ t.Error("'with SMTPS' not present")
|
|
|
+ }
|
|
|
+
|
|
|
+ if !strings.Contains(githubIssue198data, "from 127.0.0.1") {
|
|
|
+ t.Error("'from 127.0.0.1' not present")
|
|
|
+ }
|
|
|
+
|
|
|
+ /////////////////////
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ // Test with EHLO
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ line = sendMessage("EHLO", true, w, t, line, r, err, client)
|
|
|
+ if !strings.Contains(githubIssue198data, " ESMTPS ") {
|
|
|
+ t.Error("'with ESMTPS' not present")
|
|
|
+ }
|
|
|
+ /////////////////////
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // Test with EHLO & no TLS
|
|
|
+
|
|
|
+ line = sendMessage("EHLO", false, w, t, line, r, err, client)
|
|
|
+
|
|
|
+ /////////////////////
|
|
|
+
|
|
|
+ if !strings.Contains(githubIssue198data, " ESMTP ") {
|
|
|
+ t.Error("'with ESTMP' not present")
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("QUIT"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ expected := "221 2.0.0 Bye"
|
|
|
+ if strings.Index(line, expected) != 0 {
|
|
|
+ t.Error("expected", expected, "but got:", line)
|
|
|
+ }
|
|
|
+ wg.Wait() // wait for handleClient to exit
|
|
|
+}
|
|
|
+
|
|
|
+func sendMessage(greet string, TLS bool, w *textproto.Writer, t *testing.T, line string, r *textproto.Reader, err error, client *client) string {
|
|
|
+ if err := w.PrintfLine(greet + " test.test.com"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ for {
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if strings.Index(line, "250 ") == 0 {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ if strings.Index(line, "250") != 0 {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("MAIL FROM: [email protected]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RCPT TO: <hi@[ipv6:2001:DB8::FF00:42:8329]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ client.Hashes = append(client.Hashes, "abcdef1526777763")
|
|
|
+ client.TLS = TLS
|
|
|
+ if err := w.PrintfLine("DATA"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if err := w.PrintfLine("Subject: Test subject\r\n\r\nHello Sir,\nThis is a test.\r\n."); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ return line
|
|
|
+}
|
|
|
+
|
|
|
+func TestGithubIssue199(t *testing.T) {
|
|
|
+ var mainlog log.Logger
|
|
|
+ var logOpenError error
|
|
|
+ defer cleanTestArtifacts(t)
|
|
|
+ sc := getMockServerConfig()
|
|
|
+ mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
|
|
|
+ if logOpenError != nil {
|
|
|
+ mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
|
|
|
+ }
|
|
|
+ conn, server := getMockServerConn(sc, t)
|
|
|
+ server.backend().Start()
|
|
|
+
|
|
|
+ server.setAllowedHosts([]string{"grr.la", "fake.com", "[1.1.1.1]", "[2001:db8::8a2e:370:7334]", "saggydimes.test.com"})
|
|
|
+
|
|
|
+ client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(1)
|
|
|
+ go func() {
|
|
|
+ server.handleClient(client)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+ // Wait for the greeting from the server
|
|
|
+ r := textproto.NewReader(bufio.NewReader(conn.Client))
|
|
|
+ line, _ := r.ReadLine()
|
|
|
+ // fmt.Println(line)
|
|
|
+ w := textproto.NewWriter(bufio.NewWriter(conn.Client))
|
|
|
+ if err := w.PrintfLine("HELO test"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // case 1
|
|
|
+ if err := w.PrintfLine(
|
|
|
+ "MAIL FROM: <\" yo-- man wazz'''up? surprise surprise, this is [email protected] \"@example.com>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ // [SPACE][SPACE]yo--[SPACE]man[SPACE]wazz'''up?[SPACE]surprise[SPACE]surprise,[SPACE]this[SPACE]is[SPACE][email protected][SPACE]
|
|
|
+ if client.parser.LocalPart != " yo-- man wazz'''up? surprise surprise, this is [email protected] " {
|
|
|
+ t.Error("expecting local part: [ yo-- man wazz'''up? surprise surprise, this is [email protected] ], got client.parser.LocalPart")
|
|
|
+ }
|
|
|
+ if !client.parser.LocalPartQuotes {
|
|
|
+ t.Error("was expecting client.parser.LocalPartQuotes true, got false")
|
|
|
+ }
|
|
|
+ // from should just as above but without angle brackets <>
|
|
|
+ if from := client.MailFrom.String(); from != "\" yo-- man wazz'''up? surprise surprise, this is [email protected] \"@example.com" {
|
|
|
+ t.Error("mail from was:", from)
|
|
|
+ }
|
|
|
+ if line != "250 2.1.0 OK" {
|
|
|
+ t.Error("line did not have: 250 2.1.0 OK, got", line)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // case 2, address literal mailboxes
|
|
|
+ if err := w.PrintfLine("MAIL FROM: <hi@[1.1.1.1]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // stringer should be aware its an ip and return the host part in angle brackets
|
|
|
+ if from := client.MailFrom.String(); from != "hi@[1.1.1.1]" {
|
|
|
+ t.Error("mail from was:", from)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // case 3
|
|
|
+
|
|
|
+ if err := w.PrintfLine("MAIL FROM: <hi@[IPv6:2001:0db8:0000:0000:0000:8a2e:0370:7334]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // stringer should be aware its an ip and return the host part in angle brackets, and ipv6 should be normalized
|
|
|
+ if from := client.MailFrom.String(); from != "hi@[2001:db8::8a2e:370:7334]" {
|
|
|
+ t.Error("mail from was:", from)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // case 4
|
|
|
+ // rcpt to: <hi@[IPv6:2001:0db8:0000:0000:0000:ff00:0042:8329]>
|
|
|
+
|
|
|
+ if err := w.PrintfLine("MAIL FROM: <>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RCPT TO: <Postmaster>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // stringer should return an empty string
|
|
|
+ if from := client.MailFrom.String(); from != "" {
|
|
|
+ t.Error("mail from was:", from)
|
|
|
+ }
|
|
|
+
|
|
|
+ // note here the saggydimes.test.com was added because no host was specified in the RCPT TO command
|
|
|
+ if rcpt := client.RcptTo[0].String(); rcpt != "[email protected]" {
|
|
|
+ t.Error("mail from was:", rcpt)
|
|
|
+ }
|
|
|
+
|
|
|
+ // additional cases
|
|
|
+
|
|
|
+ /*
|
|
|
+ user part:
|
|
|
+ " al\ph\a "@grr.la should be " alpha "@grr.la.
|
|
|
+ "alpha"@grr.la should be [email protected].
|
|
|
+ "alp\h\a"@grr.la should be [email protected].
|
|
|
+ */
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RCPT TO: <\" al\\ph\\a \"@grr.la>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if client.RcptTo[0].User != " alpha " {
|
|
|
+ t.Error(client.RcptTo[0].User)
|
|
|
+ }
|
|
|
+
|
|
|
+ // the unnecessary \\ should be removed
|
|
|
+ if rcpt := client.RcptTo[0].String(); rcpt != "\" alpha \"@grr.la" {
|
|
|
+ t.Error(rcpt)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RCPT TO: <\"alpha\"@grr.la>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // we don't need to quote, so stringer should return without the quotes
|
|
|
+ if rcpt := client.RcptTo[0].String(); rcpt != "[email protected]" {
|
|
|
+ t.Error(rcpt)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RSET"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RCPT TO: <\"a\\l\\pha\"@grr.la>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // we don't need to quote, so stringer should return without the quotes
|
|
|
+ if rcpt := client.RcptTo[0].String(); rcpt != "[email protected]" {
|
|
|
+ t.Error(rcpt)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("QUIT"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ wg.Wait() // wait for handleClient to exit
|
|
|
+}
|
|
|
+
|
|
|
+func TestGithubIssue200(t *testing.T) {
|
|
|
+ var mainlog log.Logger
|
|
|
+ var logOpenError error
|
|
|
+ defer cleanTestArtifacts(t)
|
|
|
+ sc := getMockServerConfig()
|
|
|
+ mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
|
|
|
+ if logOpenError != nil {
|
|
|
+ mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
|
|
|
+ }
|
|
|
+ conn, server := getMockServerConn(sc, t)
|
|
|
+ server.backend().Start()
|
|
|
+ server.setAllowedHosts([]string{"1.1.1.1", "[2001:DB8::FF00:42:8329]"})
|
|
|
+
|
|
|
+ client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(1)
|
|
|
+ go func() {
|
|
|
+ server.handleClient(client)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+ // Wait for the greeting from the server
|
|
|
+ r := textproto.NewReader(bufio.NewReader(conn.Client))
|
|
|
+ line, _ := r.ReadLine()
|
|
|
+ // fmt.Println(line)
|
|
|
+ w := textproto.NewWriter(bufio.NewWriter(conn.Client))
|
|
|
+ if err := w.PrintfLine("HELO test\"><script>alert('hi')</script>test.com"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if line != "550 5.5.2 Syntax error" {
|
|
|
+ t.Error("line expected to be: 550 5.5.2 Syntax error, got", line)
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("HELO test.com"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if !strings.Contains(line, "250") {
|
|
|
+ t.Error("line did not have 250 code, got", line)
|
|
|
+ }
|
|
|
+ if err := w.PrintfLine("QUIT"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ //fmt.Println("line is:", line)
|
|
|
+ expected := "221 2.0.0 Bye"
|
|
|
+ if strings.Index(line, expected) != 0 {
|
|
|
+ t.Error("expected", expected, "but got:", line)
|
|
|
+ }
|
|
|
+ wg.Wait() // wait for handleClient to exit
|
|
|
+}
|
|
|
+
|
|
|
+func TestGithubIssue201(t *testing.T) {
|
|
|
+ var mainlog log.Logger
|
|
|
+ var logOpenError error
|
|
|
+ defer cleanTestArtifacts(t)
|
|
|
+ sc := getMockServerConfig()
|
|
|
+ mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
|
|
|
+ if logOpenError != nil {
|
|
|
+ mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
|
|
|
+ }
|
|
|
+ conn, server := getMockServerConn(sc, t)
|
|
|
+ server.backend().Start()
|
|
|
+ // note that saggydimes.test.com is the hostname of the server, it comes form the config
|
|
|
+ // it will be used for rcpt to:<postmaster> which does not specify a host
|
|
|
+ server.setAllowedHosts([]string{"a.com", "saggydimes.test.com"})
|
|
|
+
|
|
|
+ client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5))
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ wg.Add(1)
|
|
|
+ go func() {
|
|
|
+ server.handleClient(client)
|
|
|
+ wg.Done()
|
|
|
+ }()
|
|
|
+ // Wait for the greeting from the server
|
|
|
+ r := textproto.NewReader(bufio.NewReader(conn.Client))
|
|
|
+ line, _ := r.ReadLine()
|
|
|
+ // fmt.Println(line)
|
|
|
+ w := textproto.NewWriter(bufio.NewWriter(conn.Client))
|
|
|
+ if err := w.PrintfLine("HELO test"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+
|
|
|
+ // case 1
|
|
|
+ if err := w.PrintfLine("RCPT TO: <[email protected]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if line != "250 2.1.5 OK" {
|
|
|
+ t.Error("line did not have: 250 2.1.5 OK, got", line)
|
|
|
+ }
|
|
|
+ // case 2
|
|
|
+ if err := w.PrintfLine("RCPT TO: <[email protected]>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if line != "454 4.1.1 Error: Relay access denied: not-a.com" {
|
|
|
+ t.Error("line is not:454 4.1.1 Error: Relay access denied: not-a.com, got", line)
|
|
|
+ }
|
|
|
+ // case 3 (no host specified)
|
|
|
+
|
|
|
+ if err := w.PrintfLine("RCPT TO: <poSTmAsteR>"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if line != "250 2.1.5 OK" {
|
|
|
+ t.Error("line is not:[250 2.1.5 OK], got", line)
|
|
|
+ }
|
|
|
+
|
|
|
+ // case 4
|
|
|
+ if err := w.PrintfLine("RCPT TO: <\"po\\ST\\mAs\\t\\eR\">"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ if line != "250 2.1.5 OK" {
|
|
|
+ t.Error("line is not:[250 2.1.5 OK], got", line)
|
|
|
+ }
|
|
|
+ // the local part should be just "postmaster" (normalized)
|
|
|
+ if client.parser.LocalPart != "postmaster" {
|
|
|
+ t.Error("client.parser.LocalPart was not postmaster, got:", client.parser.LocalPart)
|
|
|
+ }
|
|
|
+
|
|
|
+ if client.parser.LocalPartQuotes {
|
|
|
+ t.Error("client.parser.LocalPartQuotes was true, expecting false")
|
|
|
+ }
|
|
|
+
|
|
|
+ if err := w.PrintfLine("QUIT"); err != nil {
|
|
|
+ t.Error(err)
|
|
|
+ }
|
|
|
+ line, _ = r.ReadLine()
|
|
|
+ //fmt.Println("line is:", line)
|
|
|
+ expected := "221 2.0.0 Bye"
|
|
|
+ if strings.Index(line, expected) != 0 {
|
|
|
+ t.Error("expected", expected, "but got:", line)
|
|
|
+ }
|
|
|
+ wg.Wait() // wait for handleClient to exit
|
|
|
+}
|
|
|
+
|
|
|
func TestXClient(t *testing.T) {
|
|
|
var mainlog log.Logger
|
|
|
var logOpenError error
|
|
@@ -552,6 +1096,9 @@ func TestAllowsHosts(t *testing.T) {
|
|
|
"*.test",
|
|
|
"wild*.card",
|
|
|
"multiple*wild*cards.*",
|
|
|
+ "[::FFFF:C0A8:1]", // ip4 in ipv6 format. It's actually 192.168.0.1
|
|
|
+ "[2001:db8::ff00:42:8329]", // same as 2001:0db8:0000:0000:0000:ff00:0042:8329
|
|
|
+ "[127.0.0.1]",
|
|
|
}
|
|
|
s.setAllowedHosts(allowedHosts)
|
|
|
|
|
@@ -572,6 +1119,19 @@ func TestAllowsHosts(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ testTableIP := map[string]bool{
|
|
|
+
|
|
|
+ "192.168.0.1": true,
|
|
|
+ "2001:0db8:0000:0000:0000:ff00:0042:8329": true,
|
|
|
+ "127.0.0.1": true,
|
|
|
+ }
|
|
|
+
|
|
|
+ for host, allows := range testTableIP {
|
|
|
+ if res := s.allowsIp(net.ParseIP(host)); res != allows {
|
|
|
+ t.Error(host, ": expected", allows, "but got", res)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// only wildcard - should match anything
|
|
|
s.setAllowedHosts([]string{"*"})
|
|
|
if !s.allowsHost("match.me") {
|