server_test.go 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. package guerrilla
  2. import (
  3. "os"
  4. "testing"
  5. "time"
  6. "bufio"
  7. "net/textproto"
  8. "strings"
  9. "sync"
  10. "crypto/tls"
  11. "fmt"
  12. "io/ioutil"
  13. "net"
  14. "github.com/flashmob/go-guerrilla/backends"
  15. "github.com/flashmob/go-guerrilla/log"
  16. "github.com/flashmob/go-guerrilla/mail"
  17. "github.com/flashmob/go-guerrilla/mocks"
  18. )
  19. // getMockServerConfig gets a mock ServerConfig struct used for creating a new server
  20. func getMockServerConfig() *ServerConfig {
  21. sc := &ServerConfig{
  22. IsEnabled: true, // not tested here
  23. Hostname: "saggydimes.test.com",
  24. MaxSize: 1024, // smtp message max size
  25. TLS: ServerTLSConfig{
  26. PrivateKeyFile: "./tests/mail.guerrillamail.com.key.pem",
  27. PublicKeyFile: "./tests/mail.guerrillamail.com.cert.pem",
  28. StartTLSOn: true,
  29. AlwaysOn: false,
  30. },
  31. Timeout: 5,
  32. ListenInterface: "127.0.0.1:2529",
  33. MaxClients: 30, // not tested here
  34. LogFile: "./tests/testlog",
  35. }
  36. return sc
  37. }
  38. // getMockServerConn gets a new server using sc. Server will be using a mocked TCP connection
  39. // using the dummy backend
  40. // RCP TO command only allows test.com host
  41. func getMockServerConn(sc *ServerConfig, t *testing.T) (*mocks.Conn, *server) {
  42. var logOpenError error
  43. var mainlog log.Logger
  44. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  45. if logOpenError != nil {
  46. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  47. }
  48. bcfg := backends.BackendConfig{
  49. backends.ConfigProcessors.String(): {
  50. "debugger": {"log_received_mails": true},
  51. },
  52. backends.ConfigGateways.String(): {
  53. backends.DefaultGateway: {"save_workers_size": 1},
  54. },
  55. }
  56. backend, err := backends.New(backends.DefaultGateway,
  57. bcfg,
  58. mainlog)
  59. if err != nil {
  60. t.Error("new dummy backend failed because:", err)
  61. }
  62. server, err := newServer(sc, backend, mainlog, 0)
  63. if err != nil {
  64. //t.Error("new server failed because:", err)
  65. } else {
  66. server.setAllowedHosts([]string{"test.com"})
  67. }
  68. conn := mocks.NewConn()
  69. return conn, server
  70. }
  71. // test the RootCAs tls config setting
  72. var rootCAPK = `-----BEGIN CERTIFICATE-----
  73. MIIDqjCCApKgAwIBAgIJALh2TrsBR5MiMA0GCSqGSIb3DQEBCwUAMGkxCzAJBgNV
  74. BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEhMB8G
  75. A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhv
  76. c3QwIBcNMTgwNTE4MDYzOTU2WhgPMjExODA0MjQwNjM5NTZaMGkxCzAJBgNVBAYT
  77. AlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEhMB8GA1UE
  78. CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3Qw
  79. ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCcb0ulYT1o5ysor5UtWYW
  80. q/ZY3PyK3/4YBZq5JoX4xk7GNQQ+3p/Km7QPoBXfgjFLZXEV2R0bE5hHMXfLa5Xb
  81. 64acb9VqCqDvPFXcaNP4rEdBKDVN2p0PEi917tcKBSrZn5Yl+iOhtcBpQDvhHgn/
  82. 9MdmIAKB3+yK+4l9YhT40XfDXCQqzfg4XcNaEgTzZHcDJz+KjWJuJChprcx27MTI
  83. Ndxs9nmFA2rK16rjgjtwjZ4t9dXsljdOcx59s6dIQ0GnEM8qdKxi/vEx4+M/hbGf
  84. v7H75LsuKRrVJINAmfy9fmc6VAXjFU0ZVxGK5eVnzsh/hY08TSSrlCCKAJpksjJz
  85. AgMBAAGjUzBRMB0GA1UdDgQWBBSZsYWs+8FYe4z4c6LLmFB4TeeV/jAfBgNVHSME
  86. GDAWgBSZsYWs+8FYe4z4c6LLmFB4TeeV/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
  87. SIb3DQEBCwUAA4IBAQAcXt/FaILkOCMj8bTUx42vi2N9ZTiEuRbYi24IyGOokbDR
  88. pSsIxiz+HDPUuX6/X/mHidl24aS9wdv5JTXMr44/BeGK1WC7gMueZBxAqONpaG1Q
  89. VU0e3q1YwXKcupKQ7kVWl0fuY3licv0+s4zBcTLKkmWAYqsb/n0KtCMyqewi+Rqa
  90. Zj5Z3OcWOq9Ad9fZWKcG8k/sgeTk9z0X1mZcEyWWxqsUmxvN+SdWLoug1xJVVbMN
  91. CipZ0vBIi9KOhQgzuIFhoTcd6myUtov52/EFqlX6UuFpY2gEWw/f/yu+SI08v4w9
  92. KwxgAKBkhx2JYZKtu1EsPIMDyS0aahcDnHqnrGAi
  93. -----END CERTIFICATE-----`
  94. var clientPrvKey = `-----BEGIN RSA PRIVATE KEY-----
  95. MIIEowIBAAKCAQEA5ZLmMBdKkVyVmN0VhDSFGvgKp24ejHPCv+wfuf3vlU9cwKfH
  96. R3vejleZAVRcidscfA0Jsub/Glsr0XwecagtpvTI+Fp1ik6sICOz+VW3958qaAi8
  97. TjbUMjcDHJeSLcjr725CH5uIvhRzR+daYaJQhAcL2MEt8M9WIF6AjtDZEH9R6oM8
  98. t5FkO0amImlnipYXNBFghmzkZzfGXXRQLw2A+u6keLcjCrn9h2BaofGIjQfYcu/3
  99. fH4cIFR4z/soGKameqnCUz7dWmbf4tAI+8QR0VXXBKhiHDm98tPSeH994hC52Uul
  100. rjEVcM5Uox5hazS2PK06oSc1YuFZONqeeGqj6wIDAQABAoIBADERzRHKaK3ZVEBw
  101. QQEZGLpC+kP/TZhHxgCvv7hJhsQrSnADbJzi5RcXsiSOm5j7tILvZntO1IgVpLAK
  102. D5fLkrZ069/pteXyGuhjuTw6DjBnXPEPrPAq2ABDse6SlzQiFgv/TTLkU74NMPbV
  103. hIQJ5ZvSxb12zRMDviz9Bg2ApmTX6k2iPjQBnEHgKzb64IdMcEb5HE1qNt0v0lRA
  104. sGBMZZKQWbt2m0pSbAbnB3S9GcpJkRgFFMdTaUScIWO6ICT2hBP2pw2/4M2Zrmlt
  105. bsyWu9uswBzhvu+/pg2E66V6mji0EzDMlXqjlO5jro6t7P33t1zkd/i/ykKmtDLp
  106. IpR94UECgYEA9Y4EIjOyaBWJ6TRQ6a/tehGPbwIOgvEiTYXRJqdU49qn/i4YZjSm
  107. F4iibJz+JeOIQXSwa9F7gRlaspIuHgIJoer7BrITMuhr+afqMLkxK0pijul/qAbm
  108. HdpFn8IxjpNu4/GoAENbEVy50SMST9yWh5ulEkHHftd4/NJKoJQ2PZ8CgYEA71bb
  109. lFVh1MFclxRKECmpyoqUAzwGlMoHJy/jaBYuWG4X7rzxqDRrgPH3as6gXpRiSZ+K
  110. 5fC+wcU7dKnHtJOkBDk6J5ev2+hbwg+yq3w4+l3bPDvf2TJyXjXjRDZo12pxFD58
  111. ybCOF6ItbIDXqT5pvo3PMjgMwu1Ycie+h6hA3jUCgYEAsq93XpQT/R2/T44cWxEE
  112. VFG2+GacvLhP5+26ttAJPA1/Nb3BT458Vp+84iCT6GpcWpVZU/wKTXVvxIYPPRLq
  113. g4MEzGiFBASRngiMqIv6ta/ZbHmJxXHPvmV5SLn9aezrQsA1KovZFxdMuF03FBpH
  114. B8NBKbnoO+r8Ra2ZVKTFm60CgYAZw8Dpi/N3IsWj4eRDLyj/C8H5Qyn2NHVmq4oQ
  115. d2rPzDI5Wg+tqs7z15hp4Ap1hAW8pTcfn7X5SBEpculzr/0VE1AGWRbuVmoiTuxN
  116. 95ZupVHnfw6O5BZZu/VWL4FDx0qbAksOrznso2G+b3RH3NcnUz69yjjddw1xZIPn
  117. OJ6bDQKBgDUcWYu/2amU18D5vJpppUgRq2084WPUeXsaniTbmWfOC8NAn8CKLY0N
  118. V4yGSu98apDuqEVqL0VFQEgqK+5KTvRdXXYi36XYRbbVUgV13xveq2YTvjNbPM60
  119. QWG9YmgH7hVYGusuh5nQeS0qiIpwyws2H5mBVrGXrQ1Xb0MLWj8/
  120. -----END RSA PRIVATE KEY-----`
  121. // signed using the Root (rootCAPK)
  122. var clientPubKey = `-----BEGIN CERTIFICATE-----
  123. MIIDWDCCAkACCQCHoh4OvUySOzANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJV
  124. UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxITAfBgNVBAoM
  125. GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MCAX
  126. DTE4MDUxODA2NDQ0NVoYDzMwMTcwOTE4MDY0NDQ1WjBxMQswCQYDVQQGEwJVUzET
  127. MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEhMB8G
  128. A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhv
  129. c3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDlkuYwF0qRXJWY3RWE
  130. NIUa+Aqnbh6Mc8K/7B+5/e+VT1zAp8dHe96OV5kBVFyJ2xx8DQmy5v8aWyvRfB5x
  131. qC2m9Mj4WnWKTqwgI7P5Vbf3nypoCLxONtQyNwMcl5ItyOvvbkIfm4i+FHNH51ph
  132. olCEBwvYwS3wz1YgXoCO0NkQf1Hqgzy3kWQ7RqYiaWeKlhc0EWCGbORnN8ZddFAv
  133. DYD67qR4tyMKuf2HYFqh8YiNB9hy7/d8fhwgVHjP+ygYpqZ6qcJTPt1aZt/i0Aj7
  134. xBHRVdcEqGIcOb3y09J4f33iELnZS6WuMRVwzlSjHmFrNLY8rTqhJzVi4Vk42p54
  135. aqPrAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAIQmlo8iCpyYggkbpfDmThBPHfy1
  136. cZcCi/tRFoFe1ccwn2ezLMIKmW38ZebiroawwqrZgU6AP+dMxVKLMjpyLPSrpFKa
  137. 3o/LbVF7qMfH8/y2q8t7javd6rxoENH9uxLyHhauzI1iWy0whoDWBNiZrPBTBCjq
  138. jDGZARZqGyrPeXi+RNe1cMvZCxAFy7gqEtWFLWWrp0gYNPvxkHhhQBrUcF+8T/Nf
  139. 9G4hKZSN/KAgC0CNBVuNrdyNc3l8H66BfwwL5X0+pesBYZM+MEfmBZOo+p7OWx2r
  140. ug8tR8eSL1vGleONtFRBUVG7NbtjhBf9FhvPZcSRR10od/vWHku9E01i4xg=
  141. -----END CERTIFICATE-----`
  142. func truncateIfExists(filename string) error {
  143. if _, err := os.Stat(filename); !os.IsNotExist(err) {
  144. return os.Truncate(filename, 0)
  145. }
  146. return nil
  147. }
  148. func deleteIfExists(filename string) error {
  149. if _, err := os.Stat(filename); !os.IsNotExist(err) {
  150. return os.Remove(filename)
  151. }
  152. return nil
  153. }
  154. func cleanTestArtifacts(t *testing.T) {
  155. if err := deleteIfExists("rootca.test.pem"); err != nil {
  156. t.Error(err)
  157. }
  158. if err := deleteIfExists("client.test.key"); err != nil {
  159. t.Error(err)
  160. }
  161. if err := deleteIfExists("client.test.pem"); err != nil {
  162. t.Error(err)
  163. }
  164. if err := deleteIfExists("./tests/mail.guerrillamail.com.key.pem"); err != nil {
  165. t.Error(err)
  166. }
  167. if err := deleteIfExists("./tests/mail.guerrillamail.com.cert.pem"); err != nil {
  168. t.Error(err)
  169. }
  170. if err := deleteIfExists("./tests/different-go-guerrilla.pid"); err != nil {
  171. t.Error(err)
  172. }
  173. if err := deleteIfExists("./tests/go-guerrilla.pid"); err != nil {
  174. t.Error(err)
  175. }
  176. if err := deleteIfExists("./tests/go-guerrilla2.pid"); err != nil {
  177. t.Error(err)
  178. }
  179. if err := deleteIfExists("./tests/pidfile.pid"); err != nil {
  180. t.Error(err)
  181. }
  182. if err := deleteIfExists("./tests/pidfile2.pid"); err != nil {
  183. t.Error(err)
  184. }
  185. if err := truncateIfExists("./tests/testlog"); err != nil {
  186. t.Error(err)
  187. }
  188. if err := truncateIfExists("./tests/testlog2"); err != nil {
  189. t.Error(err)
  190. }
  191. }
  192. func TestTLSConfig(t *testing.T) {
  193. defer cleanTestArtifacts(t)
  194. if err := ioutil.WriteFile("rootca.test.pem", []byte(rootCAPK), 0644); err != nil {
  195. t.Fatal("couldn't create rootca.test.pem file.", err)
  196. return
  197. }
  198. if err := ioutil.WriteFile("client.test.key", []byte(clientPrvKey), 0644); err != nil {
  199. t.Fatal("couldn't create client.test.key file.", err)
  200. return
  201. }
  202. if err := ioutil.WriteFile("client.test.pem", []byte(clientPubKey), 0644); err != nil {
  203. t.Fatal("couldn't create client.test.pem file.", err)
  204. return
  205. }
  206. s := server{}
  207. s.setConfig(&ServerConfig{
  208. TLS: ServerTLSConfig{
  209. StartTLSOn: true,
  210. PrivateKeyFile: "client.test.key",
  211. PublicKeyFile: "client.test.pem",
  212. RootCAs: "rootca.test.pem",
  213. ClientAuthType: "NoClientCert",
  214. Curves: []string{"P521", "P384"},
  215. Ciphers: []string{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"},
  216. Protocols: []string{"tls1.0", "tls1.2"},
  217. },
  218. })
  219. if err := s.configureTLS(); err != nil {
  220. t.Error(err)
  221. }
  222. c := s.tlsConfigStore.Load().(*tls.Config)
  223. if len(c.CurvePreferences) != 2 {
  224. t.Error("c.CurvePreferences should have two elements")
  225. } else if c.CurvePreferences[0] != tls.CurveP521 && c.CurvePreferences[1] != tls.CurveP384 {
  226. t.Error("c.CurvePreferences curves not setup")
  227. }
  228. if !strings.Contains(string(c.RootCAs.Subjects()[0]), "Mountain View") {
  229. t.Error("c.RootCAs not correctly set")
  230. }
  231. if c.ClientAuth != tls.NoClientCert {
  232. t.Error("c.ClientAuth should be tls.NoClientCert")
  233. }
  234. if len(c.CipherSuites) != 2 {
  235. t.Error("c.CipherSuites length should be 2")
  236. }
  237. if c.CipherSuites[0] != tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 && c.CipherSuites[1] != tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA {
  238. t.Error("c.CipherSuites not correctly set ")
  239. }
  240. if c.MinVersion != tls.VersionTLS10 {
  241. t.Error("c.MinVersion should be tls.VersionTLS10")
  242. }
  243. if c.MaxVersion != tls.VersionTLS12 {
  244. t.Error("c.MinVersion should be tls.VersionTLS10")
  245. }
  246. if c.PreferServerCipherSuites != false {
  247. t.Error("PreferServerCipherSuites should be false")
  248. }
  249. }
  250. func TestHandleClient(t *testing.T) {
  251. var mainlog log.Logger
  252. var logOpenError error
  253. defer cleanTestArtifacts(t)
  254. sc := getMockServerConfig()
  255. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  256. if logOpenError != nil {
  257. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  258. }
  259. conn, server := getMockServerConn(sc, t)
  260. // call the serve.handleClient() func in a goroutine.
  261. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  262. var wg sync.WaitGroup
  263. wg.Add(1)
  264. go func() {
  265. server.handleClient(client)
  266. wg.Done()
  267. }()
  268. // Wait for the greeting from the server
  269. r := textproto.NewReader(bufio.NewReader(conn.Client))
  270. line, _ := r.ReadLine()
  271. // fmt.Println(line)
  272. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  273. if err := w.PrintfLine("HELO test.test.com"); err != nil {
  274. t.Error(err)
  275. }
  276. line, _ = r.ReadLine()
  277. //fmt.Println(line)
  278. if err := w.PrintfLine("QUIT"); err != nil {
  279. t.Error(err)
  280. }
  281. line, _ = r.ReadLine()
  282. //fmt.Println("line is:", line)
  283. expected := "221 2.0.0 Bye"
  284. if strings.Index(line, expected) != 0 {
  285. t.Error("expected", expected, "but got:", line)
  286. }
  287. wg.Wait() // wait for handleClient to exit
  288. }
  289. func TestGithubIssue197(t *testing.T) {
  290. var mainlog log.Logger
  291. var logOpenError error
  292. defer cleanTestArtifacts(t)
  293. sc := getMockServerConfig()
  294. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  295. if logOpenError != nil {
  296. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  297. }
  298. conn, server := getMockServerConn(sc, t)
  299. server.backend().Start()
  300. // we assume that 1.1.1.1 is a domain (ip-literal syntax is incorrect)
  301. // [2001:DB8::FF00:42:8329] is an address literal
  302. server.setAllowedHosts([]string{"1.1.1.1", "[2001:DB8::FF00:42:8329]"})
  303. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  304. var wg sync.WaitGroup
  305. wg.Add(1)
  306. go func() {
  307. server.handleClient(client)
  308. wg.Done()
  309. }()
  310. // Wait for the greeting from the server
  311. r := textproto.NewReader(bufio.NewReader(conn.Client))
  312. line, _ := r.ReadLine()
  313. // fmt.Println(line)
  314. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  315. if err := w.PrintfLine("HELO test.test.com"); err != nil {
  316. t.Error(err)
  317. }
  318. line, _ = r.ReadLine()
  319. // Case 1
  320. if err := w.PrintfLine("rcpt to: <hi@[1.1.1.1]>"); err != nil {
  321. t.Error(err)
  322. }
  323. line, _ = r.ReadLine()
  324. if client.parser.IP == nil {
  325. t.Error("[1.1.1.1] not parsed as address-liteal")
  326. }
  327. // case 2, should be parsed as domain
  328. if err := w.PrintfLine("rcpt to: <[email protected]>"); err != nil {
  329. t.Error(err)
  330. }
  331. line, _ = r.ReadLine()
  332. if client.parser.IP != nil {
  333. 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]>")
  334. }
  335. // case 3
  336. // prefix ipv6 is case insensitive
  337. if err := w.PrintfLine("rcpt to: <hi@[ipv6:2001:DB8::FF00:42:8329]>"); err != nil {
  338. t.Error(err)
  339. }
  340. line, _ = r.ReadLine()
  341. if client.parser.IP == nil {
  342. t.Error("[ipv6:2001:DB8::FF00:42:8329] should be parsed as an address-literal, it wasnt")
  343. }
  344. // case 4
  345. if err := w.PrintfLine("rcpt to: <hi@[IPv6:2001:0db8:0000:0000:0000:ff00:0042:8329]>"); err != nil {
  346. t.Error(err)
  347. }
  348. line, _ = r.ReadLine()
  349. if client.parser.Domain != "2001:DB8::FF00:42:8329" && client.parser.IP == nil {
  350. t.Error("[IPv6:2001:0db8:0000:0000:0000:ff00:0042:8329] is same as 2001:DB8::FF00:42:8329, lol")
  351. }
  352. if err := w.PrintfLine("QUIT"); err != nil {
  353. t.Error(err)
  354. }
  355. line, _ = r.ReadLine()
  356. //fmt.Println("line is:", line)
  357. expected := "221 2.0.0 Bye"
  358. if strings.Index(line, expected) != 0 {
  359. t.Error("expected", expected, "but got:", line)
  360. }
  361. wg.Wait() // wait for handleClient to exit
  362. }
  363. var githubIssue198data string
  364. var customBackend = func() backends.Decorator {
  365. return func(p backends.Processor) backends.Processor {
  366. return backends.ProcessWith(
  367. func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
  368. if task == backends.TaskSaveMail {
  369. githubIssue198data = e.DeliveryHeader + e.Data.String()
  370. }
  371. return p.Process(e, task)
  372. })
  373. }
  374. }
  375. // TestGithubIssue198 is an interesting test because it shows how to do an integration test for
  376. // a backend using a custom backend.
  377. func TestGithubIssue198(t *testing.T) {
  378. var mainlog log.Logger
  379. var logOpenError error
  380. defer cleanTestArtifacts(t)
  381. sc := getMockServerConfig()
  382. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  383. backends.Svc.AddProcessor("custom", customBackend)
  384. if logOpenError != nil {
  385. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  386. }
  387. conn, server := getMockServerConn(sc, t)
  388. cfg := backends.BackendConfig{}
  389. cfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_process", "HeadersParser|Header|debugger|custom")
  390. cfg.SetValue(backends.ConfigProcessors, "header", "primary_mail_host", "example.com")
  391. cfg.SetValue(backends.ConfigProcessors, "debugger", "log_received_mails", true)
  392. be, err := backends.New("default", cfg,
  393. mainlog)
  394. if err != nil {
  395. t.Error(err)
  396. return
  397. }
  398. server.setBackend(be)
  399. if err := server.backend().Start(); err != nil {
  400. t.Error(err)
  401. return
  402. }
  403. server.setAllowedHosts([]string{"1.1.1.1", "[2001:DB8::FF00:42:8329]"})
  404. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  405. client.RemoteIP = "127.0.0.1"
  406. var wg sync.WaitGroup
  407. wg.Add(1)
  408. go func() {
  409. server.handleClient(client)
  410. wg.Done()
  411. }()
  412. // Wait for the greeting from the server
  413. r := textproto.NewReader(bufio.NewReader(conn.Client))
  414. line, _ := r.ReadLine()
  415. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  416. // Test with HELO greeting
  417. line = sendMessage("HELO", true, w, t, line, r, err, client)
  418. if !strings.Contains(githubIssue198data, " SMTPS ") {
  419. t.Error("'with SMTPS' not present")
  420. }
  421. if !strings.Contains(githubIssue198data, "from 127.0.0.1") {
  422. t.Error("'from 127.0.0.1' not present")
  423. }
  424. /////////////////////
  425. if err := w.PrintfLine("RSET"); err != nil {
  426. t.Error(err)
  427. }
  428. // Test with EHLO
  429. line, _ = r.ReadLine()
  430. line = sendMessage("EHLO", true, w, t, line, r, err, client)
  431. if !strings.Contains(githubIssue198data, " ESMTPS ") {
  432. t.Error("'with ESMTPS' not present")
  433. }
  434. /////////////////////
  435. if err := w.PrintfLine("RSET"); err != nil {
  436. t.Error(err)
  437. }
  438. line, _ = r.ReadLine()
  439. // Test with EHLO & no TLS
  440. line = sendMessage("EHLO", false, w, t, line, r, err, client)
  441. /////////////////////
  442. if !strings.Contains(githubIssue198data, " ESMTP ") {
  443. t.Error("'with ESTMP' not present")
  444. }
  445. if err := w.PrintfLine("QUIT"); err != nil {
  446. t.Error(err)
  447. }
  448. line, _ = r.ReadLine()
  449. expected := "221 2.0.0 Bye"
  450. if strings.Index(line, expected) != 0 {
  451. t.Error("expected", expected, "but got:", line)
  452. }
  453. wg.Wait() // wait for handleClient to exit
  454. }
  455. func sendMessage(greet string, TLS bool, w *textproto.Writer, t *testing.T, line string, r *textproto.Reader, err error, client *client) string {
  456. if err := w.PrintfLine(greet + " test.test.com"); err != nil {
  457. t.Error(err)
  458. }
  459. for {
  460. line, _ = r.ReadLine()
  461. if strings.Index(line, "250 ") == 0 {
  462. break
  463. }
  464. if strings.Index(line, "250") != 0 {
  465. t.Error(err)
  466. }
  467. }
  468. if r.R.Buffered() > 0 {
  469. line, _ = r.ReadLine()
  470. }
  471. if err := w.PrintfLine("MAIL FROM: [email protected]>"); err != nil {
  472. t.Error(err)
  473. }
  474. line, _ = r.ReadLine()
  475. if err := w.PrintfLine("RCPT TO: <hi@[ipv6:2001:DB8::FF00:42:8329]>"); err != nil {
  476. t.Error(err)
  477. }
  478. line, _ = r.ReadLine()
  479. client.Hashes = append(client.Hashes, "abcdef1526777763"+greet)
  480. client.TLS = TLS
  481. client.QueuedId = time.Now().String()
  482. if err := w.PrintfLine("DATA"); err != nil {
  483. t.Error(err)
  484. }
  485. line, _ = r.ReadLine()
  486. if greet == "EHLO" {
  487. }
  488. if err := w.PrintfLine("Subject: Test subject" + greet + "\r\n\r\nHello Sir,\nThis is a test.\r\n."); err != nil {
  489. t.Error(err)
  490. }
  491. if r.R.Buffered() > 0 {
  492. line, _ = r.ReadLine()
  493. }
  494. line, _ = r.ReadLine()
  495. return line
  496. }
  497. func TestGithubIssue199(t *testing.T) {
  498. var mainlog log.Logger
  499. var logOpenError error
  500. defer cleanTestArtifacts(t)
  501. sc := getMockServerConfig()
  502. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  503. if logOpenError != nil {
  504. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  505. }
  506. conn, server := getMockServerConn(sc, t)
  507. server.backend().Start()
  508. server.setAllowedHosts([]string{"grr.la", "fake.com", "[1.1.1.1]", "[2001:db8::8a2e:370:7334]", "saggydimes.test.com"})
  509. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  510. var wg sync.WaitGroup
  511. wg.Add(1)
  512. go func() {
  513. server.handleClient(client)
  514. wg.Done()
  515. }()
  516. // Wait for the greeting from the server
  517. r := textproto.NewReader(bufio.NewReader(conn.Client))
  518. line, _ := r.ReadLine()
  519. // fmt.Println(line)
  520. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  521. if err := w.PrintfLine("HELO test"); err != nil {
  522. t.Error(err)
  523. }
  524. line, _ = r.ReadLine()
  525. // case 1
  526. if err := w.PrintfLine(
  527. "MAIL FROM: <\" yo-- man wazz'''up? surprise surprise, this is [email protected] \"@example.com>"); err != nil {
  528. t.Error(err)
  529. }
  530. line, _ = r.ReadLine()
  531. // [SPACE][SPACE]yo--[SPACE]man[SPACE]wazz'''up?[SPACE]surprise[SPACE]surprise,[SPACE]this[SPACE]is[SPACE][email protected][SPACE]
  532. if client.parser.LocalPart != " yo-- man wazz'''up? surprise surprise, this is [email protected] " {
  533. t.Error("expecting local part: [ yo-- man wazz'''up? surprise surprise, this is [email protected] ], got client.parser.LocalPart")
  534. }
  535. if !client.parser.LocalPartQuotes {
  536. t.Error("was expecting client.parser.LocalPartQuotes true, got false")
  537. }
  538. // from should just as above but without angle brackets <>
  539. if from := client.MailFrom.String(); from != "\" yo-- man wazz'''up? surprise surprise, this is [email protected] \"@example.com" {
  540. t.Error("mail from was:", from)
  541. }
  542. if line != "250 2.1.0 OK" {
  543. t.Error("line did not have: 250 2.1.0 OK, got", line)
  544. }
  545. if err := w.PrintfLine("RSET"); err != nil {
  546. t.Error(err)
  547. }
  548. line, _ = r.ReadLine()
  549. // case 2, address literal mailboxes
  550. if err := w.PrintfLine("MAIL FROM: <hi@[1.1.1.1]>"); err != nil {
  551. t.Error(err)
  552. }
  553. line, _ = r.ReadLine()
  554. // stringer should be aware its an ip and return the host part in angle brackets
  555. if from := client.MailFrom.String(); from != "hi@[1.1.1.1]" {
  556. t.Error("mail from was:", from)
  557. }
  558. if err := w.PrintfLine("RSET"); err != nil {
  559. t.Error(err)
  560. }
  561. line, _ = r.ReadLine()
  562. // case 3
  563. if err := w.PrintfLine("MAIL FROM: <hi@[IPv6:2001:0db8:0000:0000:0000:8a2e:0370:7334]>"); err != nil {
  564. t.Error(err)
  565. }
  566. line, _ = r.ReadLine()
  567. // stringer should be aware its an ip and return the host part in angle brackets, and ipv6 should be normalized
  568. if from := client.MailFrom.String(); from != "hi@[2001:db8::8a2e:370:7334]" {
  569. t.Error("mail from was:", from)
  570. }
  571. if err := w.PrintfLine("RSET"); err != nil {
  572. t.Error(err)
  573. }
  574. line, _ = r.ReadLine()
  575. // case 4
  576. // rcpt to: <hi@[IPv6:2001:0db8:0000:0000:0000:ff00:0042:8329]>
  577. if err := w.PrintfLine("MAIL FROM: <>"); err != nil {
  578. t.Error(err)
  579. }
  580. line, _ = r.ReadLine()
  581. if err := w.PrintfLine("RCPT TO: <Postmaster>"); err != nil {
  582. t.Error(err)
  583. }
  584. line, _ = r.ReadLine()
  585. // stringer should return an empty string
  586. if from := client.MailFrom.String(); from != "" {
  587. t.Error("mail from was:", from)
  588. }
  589. // note here the saggydimes.test.com was added because no host was specified in the RCPT TO command
  590. if rcpt := client.RcptTo[0].String(); rcpt != "[email protected]" {
  591. t.Error("mail from was:", rcpt)
  592. }
  593. // additional cases
  594. /*
  595. user part:
  596. " al\ph\a "@grr.la should be " alpha "@grr.la.
  597. "alpha"@grr.la should be [email protected].
  598. "alp\h\a"@grr.la should be [email protected].
  599. */
  600. if err := w.PrintfLine("RSET"); err != nil {
  601. t.Error(err)
  602. }
  603. line, _ = r.ReadLine()
  604. if err := w.PrintfLine("RCPT TO: <\" al\\ph\\a \"@grr.la>"); err != nil {
  605. t.Error(err)
  606. }
  607. line, _ = r.ReadLine()
  608. if client.RcptTo[0].User != " alpha " {
  609. t.Error(client.RcptTo[0].User)
  610. }
  611. // the unnecessary \\ should be removed
  612. if rcpt := client.RcptTo[0].String(); rcpt != "\" alpha \"@grr.la" {
  613. t.Error(rcpt)
  614. }
  615. if err := w.PrintfLine("RSET"); err != nil {
  616. t.Error(err)
  617. }
  618. line, _ = r.ReadLine()
  619. if err := w.PrintfLine("RCPT TO: <\"alpha\"@grr.la>"); err != nil {
  620. t.Error(err)
  621. }
  622. line, _ = r.ReadLine()
  623. // we don't need to quote, so stringer should return without the quotes
  624. if rcpt := client.RcptTo[0].String(); rcpt != "[email protected]" {
  625. t.Error(rcpt)
  626. }
  627. if err := w.PrintfLine("RSET"); err != nil {
  628. t.Error(err)
  629. }
  630. line, _ = r.ReadLine()
  631. if err := w.PrintfLine("RCPT TO: <\"a\\l\\pha\"@grr.la>"); err != nil {
  632. t.Error(err)
  633. }
  634. line, _ = r.ReadLine()
  635. // we don't need to quote, so stringer should return without the quotes
  636. if rcpt := client.RcptTo[0].String(); rcpt != "[email protected]" {
  637. t.Error(rcpt)
  638. }
  639. if err := w.PrintfLine("QUIT"); err != nil {
  640. t.Error(err)
  641. }
  642. line, _ = r.ReadLine()
  643. wg.Wait() // wait for handleClient to exit
  644. }
  645. func TestGithubIssue200(t *testing.T) {
  646. var mainlog log.Logger
  647. var logOpenError error
  648. defer cleanTestArtifacts(t)
  649. sc := getMockServerConfig()
  650. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  651. if logOpenError != nil {
  652. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  653. }
  654. conn, server := getMockServerConn(sc, t)
  655. server.backend().Start()
  656. server.setAllowedHosts([]string{"1.1.1.1", "[2001:DB8::FF00:42:8329]"})
  657. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  658. var wg sync.WaitGroup
  659. wg.Add(1)
  660. go func() {
  661. server.handleClient(client)
  662. wg.Done()
  663. }()
  664. // Wait for the greeting from the server
  665. r := textproto.NewReader(bufio.NewReader(conn.Client))
  666. line, _ := r.ReadLine()
  667. // fmt.Println(line)
  668. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  669. if err := w.PrintfLine("HELO test\"><script>alert('hi')</script>test.com"); err != nil {
  670. t.Error(err)
  671. }
  672. line, _ = r.ReadLine()
  673. if line != "550 5.5.2 Syntax error" {
  674. t.Error("line expected to be: 550 5.5.2 Syntax error, got", line)
  675. }
  676. if err := w.PrintfLine("HELO test.com"); err != nil {
  677. t.Error(err)
  678. }
  679. line, _ = r.ReadLine()
  680. if !strings.Contains(line, "250") {
  681. t.Error("line did not have 250 code, got", line)
  682. }
  683. if err := w.PrintfLine("QUIT"); err != nil {
  684. t.Error(err)
  685. }
  686. line, _ = r.ReadLine()
  687. //fmt.Println("line is:", line)
  688. expected := "221 2.0.0 Bye"
  689. if strings.Index(line, expected) != 0 {
  690. t.Error("expected", expected, "but got:", line)
  691. }
  692. wg.Wait() // wait for handleClient to exit
  693. }
  694. func TestGithubIssue201(t *testing.T) {
  695. var mainlog log.Logger
  696. var logOpenError error
  697. defer cleanTestArtifacts(t)
  698. sc := getMockServerConfig()
  699. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  700. if logOpenError != nil {
  701. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  702. }
  703. conn, server := getMockServerConn(sc, t)
  704. server.backend().Start()
  705. // note that saggydimes.test.com is the hostname of the server, it comes form the config
  706. // it will be used for rcpt to:<postmaster> which does not specify a host
  707. server.setAllowedHosts([]string{"a.com", "saggydimes.test.com"})
  708. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  709. var wg sync.WaitGroup
  710. wg.Add(1)
  711. go func() {
  712. server.handleClient(client)
  713. wg.Done()
  714. }()
  715. // Wait for the greeting from the server
  716. r := textproto.NewReader(bufio.NewReader(conn.Client))
  717. line, _ := r.ReadLine()
  718. // fmt.Println(line)
  719. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  720. if err := w.PrintfLine("HELO test"); err != nil {
  721. t.Error(err)
  722. }
  723. line, _ = r.ReadLine()
  724. // case 1
  725. if err := w.PrintfLine("RCPT TO: <[email protected]>"); err != nil {
  726. t.Error(err)
  727. }
  728. line, _ = r.ReadLine()
  729. if line != "250 2.1.5 OK" {
  730. t.Error("line did not have: 250 2.1.5 OK, got", line)
  731. }
  732. // case 2
  733. if err := w.PrintfLine("RCPT TO: <[email protected]>"); err != nil {
  734. t.Error(err)
  735. }
  736. line, _ = r.ReadLine()
  737. if line != "454 4.1.1 Error: Relay access denied: not-a.com" {
  738. t.Error("line is not:454 4.1.1 Error: Relay access denied: not-a.com, got", line)
  739. }
  740. // case 3 (no host specified)
  741. if err := w.PrintfLine("RCPT TO: <poSTmAsteR>"); err != nil {
  742. t.Error(err)
  743. }
  744. line, _ = r.ReadLine()
  745. if line != "250 2.1.5 OK" {
  746. t.Error("line is not:[250 2.1.5 OK], got", line)
  747. }
  748. // case 4
  749. if err := w.PrintfLine("RCPT TO: <\"po\\ST\\mAs\\t\\eR\">"); err != nil {
  750. t.Error(err)
  751. }
  752. line, _ = r.ReadLine()
  753. if line != "250 2.1.5 OK" {
  754. t.Error("line is not:[250 2.1.5 OK], got", line)
  755. }
  756. // the local part should be just "postmaster" (normalized)
  757. if client.parser.LocalPart != "postmaster" {
  758. t.Error("client.parser.LocalPart was not postmaster, got:", client.parser.LocalPart)
  759. }
  760. if client.parser.LocalPartQuotes {
  761. t.Error("client.parser.LocalPartQuotes was true, expecting false")
  762. }
  763. if err := w.PrintfLine("QUIT"); err != nil {
  764. t.Error(err)
  765. }
  766. line, _ = r.ReadLine()
  767. //fmt.Println("line is:", line)
  768. expected := "221 2.0.0 Bye"
  769. if strings.Index(line, expected) != 0 {
  770. t.Error("expected", expected, "but got:", line)
  771. }
  772. wg.Wait() // wait for handleClient to exit
  773. }
  774. func TestXClient(t *testing.T) {
  775. var mainlog log.Logger
  776. var logOpenError error
  777. defer cleanTestArtifacts(t)
  778. sc := getMockServerConfig()
  779. sc.XClientOn = true
  780. mainlog, logOpenError = log.GetLogger(sc.LogFile, "debug")
  781. if logOpenError != nil {
  782. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  783. }
  784. conn, server := getMockServerConn(sc, t)
  785. // call the serve.handleClient() func in a goroutine.
  786. client := NewClient(conn.Server, 1, mainlog, mail.NewPool(5), 0)
  787. var wg sync.WaitGroup
  788. wg.Add(1)
  789. go func() {
  790. server.handleClient(client)
  791. wg.Done()
  792. }()
  793. // Wait for the greeting from the server
  794. r := textproto.NewReader(bufio.NewReader(conn.Client))
  795. line, _ := r.ReadLine()
  796. // fmt.Println(line)
  797. w := textproto.NewWriter(bufio.NewWriter(conn.Client))
  798. if err := w.PrintfLine("HELO test.test.com"); err != nil {
  799. t.Error(err)
  800. }
  801. line, _ = r.ReadLine()
  802. //fmt.Println(line)
  803. if err := w.PrintfLine("XCLIENT ADDR=212.96.64.216 NAME=[UNAVAILABLE]"); err != nil {
  804. t.Error(err)
  805. }
  806. line, _ = r.ReadLine()
  807. if client.RemoteIP != "212.96.64.216" {
  808. t.Error("client.RemoteIP should be 212.96.64.216, but got:", client.RemoteIP)
  809. }
  810. expected := "250 2.1.0 OK"
  811. if strings.Index(line, expected) != 0 {
  812. t.Error("expected", expected, "but got:", line)
  813. }
  814. // try malformed input
  815. if err := w.PrintfLine("XCLIENT c"); err != nil {
  816. t.Error(err)
  817. }
  818. line, _ = r.ReadLine()
  819. expected = "250 2.1.0 OK"
  820. if strings.Index(line, expected) != 0 {
  821. t.Error("expected", expected, "but got:", line)
  822. }
  823. if err := w.PrintfLine("QUIT"); err != nil {
  824. t.Error(err)
  825. }
  826. line, _ = r.ReadLine()
  827. wg.Wait() // wait for handleClient to exit
  828. }
  829. // The backend gateway should time out after 1 second because it sleeps for 2 sec.
  830. // The transaction should wait until finished, and then test to see if we can do
  831. // a second transaction
  832. func TestGatewayTimeout(t *testing.T) {
  833. defer cleanTestArtifacts(t)
  834. bcfg := backends.BackendConfig{}
  835. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_timeout", "1s")
  836. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "val_rcpt_timeout", "1s")
  837. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_workers_size", 1)
  838. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_process", "HeadersParser|Debugger")
  839. bcfg.SetValue(backends.ConfigProcessors, "header", "primary_mail_host", "example.com")
  840. bcfg.SetValue(backends.ConfigProcessors, "debugger", "log_received_mails", true)
  841. bcfg.SetValue(backends.ConfigProcessors, "debugger", "sleep_seconds", 2)
  842. cfg := &AppConfig{
  843. LogFile: log.OutputOff.String(),
  844. AllowedHosts: []string{"grr.la"},
  845. }
  846. cfg.BackendConfig = bcfg
  847. d := Daemon{Config: cfg}
  848. err := d.Start()
  849. if err != nil {
  850. t.Error("server didn't start")
  851. } else {
  852. conn, err := net.Dial("tcp", "127.0.0.1:2525")
  853. if err != nil {
  854. return
  855. }
  856. in := bufio.NewReader(conn)
  857. str, err := in.ReadString('\n')
  858. if err != nil {
  859. t.Error(err)
  860. }
  861. if _, err := fmt.Fprint(conn, "HELO host\r\n"); err != nil {
  862. t.Error(err)
  863. }
  864. str, err = in.ReadString('\n')
  865. // perform 2 transactions
  866. // both should panic.
  867. for i := 0; i < 2; i++ {
  868. if _, err := fmt.Fprint(conn, "MAIL FROM:<[email protected]>\r\n"); err != nil {
  869. t.Error(err)
  870. }
  871. if str, err = in.ReadString('\n'); err != nil {
  872. t.Error(err)
  873. }
  874. if _, err := fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n"); err != nil {
  875. t.Error(err)
  876. }
  877. if str, err = in.ReadString('\n'); err != nil {
  878. t.Error(err)
  879. }
  880. if _, err := fmt.Fprint(conn, "DATA\r\n"); err != nil {
  881. t.Error(err)
  882. }
  883. if str, err = in.ReadString('\n'); err != nil {
  884. t.Error(err)
  885. }
  886. if _, err := fmt.Fprint(conn, "Subject: Test subject\r\n"); err != nil {
  887. t.Error(err)
  888. }
  889. if _, err := fmt.Fprint(conn, "\r\n"); err != nil {
  890. t.Error(err)
  891. }
  892. if _, err := fmt.Fprint(conn, "A an email body\r\n"); err != nil {
  893. t.Error(err)
  894. }
  895. if _, err := fmt.Fprint(conn, ".\r\n"); err != nil {
  896. t.Error(err)
  897. }
  898. str, err = in.ReadString('\n')
  899. expect := "transaction timeout"
  900. if err != nil {
  901. t.Error(err)
  902. } else if !strings.Contains(str, expect) {
  903. t.Error("Expected the reply to have'", expect, "'but got", str)
  904. }
  905. }
  906. _ = str
  907. d.Shutdown()
  908. }
  909. }
  910. // The processor will panic and gateway should recover from it
  911. func TestGatewayPanic(t *testing.T) {
  912. defer cleanTestArtifacts(t)
  913. bcfg := backends.BackendConfig{}
  914. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_timeout", "2s")
  915. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "val_rcpt_timeout", "2s")
  916. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_workers_size", 1)
  917. bcfg.SetValue(backends.ConfigGateways, backends.DefaultGateway, "save_process", "HeadersParser|Debugger")
  918. bcfg.SetValue(backends.ConfigProcessors, "header", "primary_mail_host", "example.com")
  919. bcfg.SetValue(backends.ConfigProcessors, "debugger", "log_received_mails", true)
  920. bcfg.SetValue(backends.ConfigProcessors, "debugger", "sleep_seconds", 1)
  921. cfg := &AppConfig{
  922. LogFile: log.OutputOff.String(),
  923. AllowedHosts: []string{"grr.la"},
  924. }
  925. cfg.BackendConfig = bcfg
  926. d := Daemon{Config: cfg}
  927. err := d.Start()
  928. if err != nil {
  929. t.Error("server didn't start")
  930. } else {
  931. conn, err := net.Dial("tcp", "127.0.0.1:2525")
  932. if err != nil {
  933. return
  934. }
  935. in := bufio.NewReader(conn)
  936. if _, err := in.ReadString('\n'); err != nil {
  937. t.Error(err)
  938. }
  939. if _, err := fmt.Fprint(conn, "HELO host\r\n"); err != nil {
  940. t.Error(err)
  941. }
  942. if _, err = in.ReadString('\n'); err != nil {
  943. t.Error(err)
  944. }
  945. // perform 2 transactions
  946. // both should timeout. The reason why 2 is because we want to make
  947. // sure that the client waits until processing finishes, and the
  948. // timeout event is captured.
  949. for i := 0; i < 2; i++ {
  950. if _, err := fmt.Fprint(conn, "MAIL FROM:<[email protected]>\r\n"); err != nil {
  951. t.Error(err)
  952. }
  953. if _, err = in.ReadString('\n'); err != nil {
  954. t.Error(err)
  955. }
  956. if _, err := fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n"); err != nil {
  957. t.Error(err)
  958. }
  959. if _, err = in.ReadString('\n'); err != nil {
  960. t.Error(err)
  961. }
  962. if _, err := fmt.Fprint(conn, "DATA\r\n"); err != nil {
  963. t.Error(err)
  964. }
  965. if _, err = in.ReadString('\n'); err != nil {
  966. t.Error(err)
  967. }
  968. if _, err := fmt.Fprint(conn, "Subject: Test subject\r\n"); err != nil {
  969. t.Error(err)
  970. }
  971. if _, err := fmt.Fprint(conn, "\r\n"); err != nil {
  972. t.Error(err)
  973. }
  974. if _, err := fmt.Fprint(conn, "A an email body\r\n"); err != nil {
  975. t.Error(err)
  976. }
  977. if _, err := fmt.Fprint(conn, ".\r\n"); err != nil {
  978. t.Error(err)
  979. }
  980. if str, err := in.ReadString('\n'); err != nil {
  981. t.Error(err)
  982. } else {
  983. expect := "storage failed"
  984. if !strings.Contains(str, expect) {
  985. t.Error("Expected the reply to have'", expect, "'but got", str)
  986. }
  987. }
  988. }
  989. d.Shutdown()
  990. }
  991. }
  992. func TestAllowsHosts(t *testing.T) {
  993. defer cleanTestArtifacts(t)
  994. s := server{}
  995. allowedHosts := []string{
  996. "spam4.me",
  997. "grr.la",
  998. "newhost.com",
  999. "example.*",
  1000. "*.test",
  1001. "wild*.card",
  1002. "multiple*wild*cards.*",
  1003. "[::FFFF:C0A8:1]", // ip4 in ipv6 format. It's actually 192.168.0.1
  1004. "[2001:db8::ff00:42:8329]", // same as 2001:0db8:0000:0000:0000:ff00:0042:8329
  1005. "[127.0.0.1]",
  1006. }
  1007. s.setAllowedHosts(allowedHosts)
  1008. testTable := map[string]bool{
  1009. "spam4.me": true,
  1010. "dont.match": false,
  1011. "example.com": true,
  1012. "another.example.com": false,
  1013. "anything.test": true,
  1014. "wild.card": true,
  1015. "wild.card.com": false,
  1016. "multipleXwildXcards.com": true,
  1017. }
  1018. for host, allows := range testTable {
  1019. if res := s.allowsHost(host); res != allows {
  1020. t.Error(host, ": expected", allows, "but got", res)
  1021. }
  1022. }
  1023. testTableIP := map[string]bool{
  1024. "192.168.0.1": true,
  1025. "2001:0db8:0000:0000:0000:ff00:0042:8329": true,
  1026. "127.0.0.1": true,
  1027. }
  1028. for host, allows := range testTableIP {
  1029. if res := s.allowsIp(net.ParseIP(host)); res != allows {
  1030. t.Error(host, ": expected", allows, "but got", res)
  1031. }
  1032. }
  1033. // only wildcard - should match anything
  1034. s.setAllowedHosts([]string{"*"})
  1035. if !s.allowsHost("match.me") {
  1036. t.Error("match.me: expected true but got false")
  1037. }
  1038. // turns off
  1039. s.setAllowedHosts([]string{"."})
  1040. if !s.allowsHost("match.me") {
  1041. t.Error("match.me: expected true but got false")
  1042. }
  1043. // no wilcards
  1044. s.setAllowedHosts([]string{"grr.la", "example.com"})
  1045. }