server_test.go 35 KB

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