api_test.go 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219
  1. package guerrilla
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "github.com/flashmob/go-guerrilla/backends"
  7. "github.com/flashmob/go-guerrilla/log"
  8. "github.com/flashmob/go-guerrilla/mail"
  9. "github.com/flashmob/go-guerrilla/response"
  10. "io/ioutil"
  11. "net"
  12. "os"
  13. "strings"
  14. "testing"
  15. "time"
  16. )
  17. // Test Starting smtp without setting up logger / backend
  18. func TestSMTP(t *testing.T) {
  19. done := make(chan bool)
  20. go func() {
  21. select {
  22. case <-time.After(time.Second * 40):
  23. t.Error("timeout")
  24. return
  25. case <-done:
  26. return
  27. }
  28. }()
  29. d := Daemon{}
  30. err := d.Start()
  31. if err != nil {
  32. t.Error(err)
  33. }
  34. // it should set to stderr automatically
  35. if d.Config.LogFile != log.OutputStderr.String() {
  36. t.Error("smtp.config.LogFile is not", log.OutputStderr.String())
  37. }
  38. if len(d.Config.AllowedHosts) == 0 {
  39. t.Error("smtp.config.AllowedHosts len should be 1, not 0", d.Config.AllowedHosts)
  40. }
  41. if d.Config.LogLevel != "debug" {
  42. t.Error("smtp.config.LogLevel expected'debug', it is", d.Config.LogLevel)
  43. }
  44. if len(d.Config.Servers) != 1 {
  45. t.Error("len(smtp.config.Servers) should be 1, got", len(d.Config.Servers))
  46. }
  47. time.Sleep(time.Second * 2)
  48. d.Shutdown()
  49. done <- true
  50. }
  51. // Suppressing log output
  52. func TestSMTPNoLog(t *testing.T) {
  53. // configure a default server with no log output
  54. cfg := &AppConfig{LogFile: log.OutputOff.String()}
  55. d := Daemon{Config: cfg}
  56. err := d.Start()
  57. if err != nil {
  58. t.Error(err)
  59. }
  60. time.Sleep(time.Second * 2)
  61. d.Shutdown()
  62. }
  63. // our custom server
  64. func TestSMTPCustomServer(t *testing.T) {
  65. cfg := &AppConfig{LogFile: log.OutputOff.String()}
  66. sc := ServerConfig{
  67. ListenInterface: "127.0.0.1:2526",
  68. IsEnabled: true,
  69. }
  70. cfg.Servers = append(cfg.Servers, sc)
  71. d := Daemon{Config: cfg}
  72. err := d.Start()
  73. if err != nil {
  74. t.Error("start error", err)
  75. } else {
  76. time.Sleep(time.Second * 2)
  77. d.Shutdown()
  78. }
  79. }
  80. // with a backend config
  81. func TestSMTPCustomBackend(t *testing.T) {
  82. cfg := &AppConfig{LogFile: log.OutputOff.String()}
  83. sc := ServerConfig{
  84. ListenInterface: "127.0.0.1:2526",
  85. IsEnabled: true,
  86. }
  87. cfg.Servers = append(cfg.Servers, sc)
  88. bcfg := backends.BackendConfig{
  89. "save_workers_size": 3,
  90. "save_process": "HeadersParser|Header|Hasher|Debugger",
  91. "log_received_mails": true,
  92. "primary_mail_host": "example.com",
  93. }
  94. cfg.BackendConfig = bcfg
  95. d := Daemon{Config: cfg}
  96. err := d.Start()
  97. if err != nil {
  98. t.Error("start error", err)
  99. } else {
  100. time.Sleep(time.Second * 2)
  101. d.Shutdown()
  102. }
  103. }
  104. // with a config from a json file
  105. func TestSMTPLoadFile(t *testing.T) {
  106. json := `{
  107. "log_file" : "./tests/testlog",
  108. "log_level" : "debug",
  109. "pid_file" : "tests/go-guerrilla.pid",
  110. "allowed_hosts": ["spam4.me","grr.la"],
  111. "backend_config" :
  112. {
  113. "log_received_mails" : true,
  114. "save_process": "HeadersParser|Header|Hasher|Debugger",
  115. "save_workers_size": 3
  116. },
  117. "servers" : [
  118. {
  119. "is_enabled" : true,
  120. "host_name":"mail.guerrillamail.com",
  121. "max_size": 100017,
  122. "timeout":160,
  123. "listen_interface":"127.0.0.1:2526",
  124. "max_clients": 2,
  125. "tls" : {
  126. "private_key_file":"config_test.go",
  127. "public_key_file":"config_test.go",
  128. "start_tls_on":false,
  129. "tls_always_on":false
  130. }
  131. }
  132. ]
  133. }
  134. `
  135. json2 := `{
  136. "log_file" : "./tests/testlog2",
  137. "log_level" : "debug",
  138. "pid_file" : "tests/go-guerrilla2.pid",
  139. "allowed_hosts": ["spam4.me","grr.la"],
  140. "backend_config" :
  141. {
  142. "log_received_mails" : true,
  143. "save_process": "HeadersParser|Header|Hasher|Debugger",
  144. "save_workers_size": 3
  145. },
  146. "servers" : [
  147. {
  148. "is_enabled" : true,
  149. "host_name":"mail.guerrillamail.com",
  150. "max_size": 100017,
  151. "timeout":160,
  152. "listen_interface":"127.0.0.1:2526",
  153. "max_clients": 2,
  154. "tls" : {
  155. "private_key_file":"config_test.go",
  156. "public_key_file":"config_test.go",
  157. "start_tls_on":false,
  158. "tls_always_on":false
  159. }
  160. }
  161. ]
  162. }
  163. `
  164. err := ioutil.WriteFile("goguerrilla.conf.api", []byte(json), 0644)
  165. if err != nil {
  166. t.Error("could not write guerrilla.conf.api", err)
  167. return
  168. }
  169. d := Daemon{}
  170. _, err = d.LoadConfig("goguerrilla.conf.api")
  171. if err != nil {
  172. t.Error("ReadConfig error", err)
  173. return
  174. }
  175. err = d.Start()
  176. if err != nil {
  177. t.Error("start error", err)
  178. return
  179. } else {
  180. time.Sleep(time.Second * 2)
  181. if d.Config.LogFile != "./tests/testlog" {
  182. t.Error("d.Config.LogFile != \"./tests/testlog\"")
  183. }
  184. if d.Config.PidFile != "tests/go-guerrilla.pid" {
  185. t.Error("d.Config.LogFile != tests/go-guerrilla.pid")
  186. }
  187. err := ioutil.WriteFile("goguerrilla.conf.api", []byte(json2), 0644)
  188. if err != nil {
  189. t.Error("could not write guerrilla.conf.api", err)
  190. return
  191. }
  192. if err = d.ReloadConfigFile("goguerrilla.conf.api"); err != nil {
  193. t.Error(err)
  194. }
  195. if d.Config.LogFile != "./tests/testlog2" {
  196. t.Error("d.Config.LogFile != \"./tests/testlog\"")
  197. }
  198. if d.Config.PidFile != "tests/go-guerrilla2.pid" {
  199. t.Error("d.Config.LogFile != \"go-guerrilla.pid\"")
  200. }
  201. d.Shutdown()
  202. }
  203. }
  204. func TestReopenLog(t *testing.T) {
  205. if err := os.Truncate("tests/testlog", 0); err != nil {
  206. t.Error(err)
  207. }
  208. cfg := &AppConfig{LogFile: "tests/testlog"}
  209. sc := ServerConfig{
  210. ListenInterface: "127.0.0.1:2526",
  211. IsEnabled: true,
  212. }
  213. cfg.Servers = append(cfg.Servers, sc)
  214. d := Daemon{Config: cfg}
  215. err := d.Start()
  216. if err != nil {
  217. t.Error("start error", err)
  218. } else {
  219. if err = d.ReopenLogs(); err != nil {
  220. t.Error(err)
  221. }
  222. time.Sleep(time.Second * 2)
  223. d.Shutdown()
  224. }
  225. b, err := ioutil.ReadFile("tests/testlog")
  226. if err != nil {
  227. t.Error("could not read logfile")
  228. return
  229. }
  230. if strings.Index(string(b), "re-opened log file") < 0 {
  231. t.Error("Server log did not re-opened, expecting \"re-opened log file\"")
  232. }
  233. if strings.Index(string(b), "re-opened main log file") < 0 {
  234. t.Error("Main log did not re-opened, expecting \"re-opened main log file\"")
  235. }
  236. }
  237. func TestSetConfig(t *testing.T) {
  238. if err := os.Truncate("tests/testlog", 0); err != nil {
  239. t.Error(err)
  240. }
  241. cfg := AppConfig{LogFile: "tests/testlog"}
  242. sc := ServerConfig{
  243. ListenInterface: "127.0.0.1:2526",
  244. IsEnabled: true,
  245. }
  246. cfg.Servers = append(cfg.Servers, sc)
  247. d := Daemon{Config: &cfg}
  248. // lets add a new server
  249. sc.ListenInterface = "127.0.0.1:2527"
  250. cfg.Servers = append(cfg.Servers, sc)
  251. err := d.SetConfig(cfg)
  252. if err != nil {
  253. t.Error("SetConfig returned an error:", err)
  254. return
  255. }
  256. err = d.Start()
  257. if err != nil {
  258. t.Error("start error", err)
  259. } else {
  260. time.Sleep(time.Second * 2)
  261. d.Shutdown()
  262. }
  263. b, err := ioutil.ReadFile("tests/testlog")
  264. if err != nil {
  265. t.Error("could not read logfile")
  266. return
  267. }
  268. //fmt.Println(string(b))
  269. // has 127.0.0.1:2527 started?
  270. if strings.Index(string(b), "127.0.0.1:2527") < 0 {
  271. t.Error("expecting 127.0.0.1:2527 to start")
  272. }
  273. }
  274. func TestSetConfigError(t *testing.T) {
  275. if err := os.Truncate("tests/testlog", 0); err != nil {
  276. t.Error(err)
  277. }
  278. cfg := AppConfig{LogFile: "tests/testlog"}
  279. sc := ServerConfig{
  280. ListenInterface: "127.0.0.1:2526",
  281. IsEnabled: true,
  282. }
  283. cfg.Servers = append(cfg.Servers, sc)
  284. d := Daemon{Config: &cfg}
  285. // lets add a new server with bad TLS
  286. sc.ListenInterface = "127.0.0.1:2527"
  287. sc.TLS.StartTLSOn = true
  288. sc.TLS.PublicKeyFile = "tests/testlog" // totally wrong :->
  289. sc.TLS.PrivateKeyFile = "tests/testlog" // totally wrong :->
  290. cfg.Servers = append(cfg.Servers, sc)
  291. err := d.SetConfig(cfg)
  292. if err == nil {
  293. t.Error("SetConfig should have returned an error compalning about bad tls settings")
  294. return
  295. }
  296. }
  297. var funkyLogger = func() backends.Decorator {
  298. backends.Svc.AddInitializer(
  299. backends.InitializeWith(
  300. func(backendConfig backends.BackendConfig) error {
  301. backends.Log().Info("Funky logger is up & down to funk!")
  302. return nil
  303. }),
  304. )
  305. backends.Svc.AddShutdowner(
  306. backends.ShutdownWith(
  307. func() error {
  308. backends.Log().Info("The funk has been stopped!")
  309. return nil
  310. }),
  311. )
  312. return func(p backends.Processor) backends.Processor {
  313. return backends.ProcessWith(
  314. func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
  315. if task == backends.TaskValidateRcpt {
  316. // log the last recipient appended to e.Rcpt
  317. backends.Log().Infof(
  318. "another funky recipient [%s]",
  319. e.RcptTo[len(e.RcptTo)-1])
  320. // if valid then forward call to the next processor in the chain
  321. return p.Process(e, task)
  322. // if invalid, return a backend result
  323. //return backends.NewResult(response.Canned.FailRcptCmd), nil
  324. } else if task == backends.TaskSaveMail {
  325. backends.Log().Info("Another funky email!")
  326. }
  327. return p.Process(e, task)
  328. })
  329. }
  330. }
  331. // How about a custom processor?
  332. func TestSetAddProcessor(t *testing.T) {
  333. if err := os.Truncate("tests/testlog", 0); err != nil {
  334. t.Error(err)
  335. }
  336. cfg := &AppConfig{
  337. LogFile: "tests/testlog",
  338. AllowedHosts: []string{"grr.la"},
  339. BackendConfig: backends.BackendConfig{
  340. "save_process": "HeadersParser|Debugger|FunkyLogger",
  341. "validate_process": "FunkyLogger",
  342. },
  343. }
  344. d := Daemon{Config: cfg}
  345. d.AddProcessor("FunkyLogger", funkyLogger)
  346. if err := d.Start(); err != nil {
  347. t.Error(err)
  348. }
  349. // lets have a talk with the server
  350. if err := talkToServer("127.0.0.1:2525", ""); err != nil {
  351. t.Error(err)
  352. }
  353. d.Shutdown()
  354. b, err := ioutil.ReadFile("tests/testlog")
  355. if err != nil {
  356. t.Error("could not read logfile")
  357. return
  358. }
  359. // lets check for fingerprints
  360. if strings.Index(string(b), "another funky recipient") < 0 {
  361. t.Error("did not log: another funky recipient")
  362. }
  363. if strings.Index(string(b), "Another funky email!") < 0 {
  364. t.Error("Did not log: Another funky email!")
  365. }
  366. if strings.Index(string(b), "Funky logger is up & down to funk") < 0 {
  367. t.Error("Did not log: Funky logger is up & down to funk")
  368. }
  369. if strings.Index(string(b), "The funk has been stopped!") < 0 {
  370. t.Error("Did not log:The funk has been stopped!")
  371. }
  372. }
  373. func talkToServer(address string, body string) (err error) {
  374. conn, err := net.Dial("tcp", address)
  375. if err != nil {
  376. return
  377. }
  378. in := bufio.NewReader(conn)
  379. str, err := in.ReadString('\n')
  380. if err != nil {
  381. return err
  382. }
  383. _, err = fmt.Fprint(conn, "HELO maildiranasaurustester\r\n")
  384. if err != nil {
  385. return err
  386. }
  387. str, err = in.ReadString('\n')
  388. if err != nil {
  389. return err
  390. }
  391. _, err = fmt.Fprint(conn, "MAIL FROM:<[email protected]>\r\n")
  392. if err != nil {
  393. return err
  394. }
  395. str, err = in.ReadString('\n')
  396. if err != nil {
  397. return err
  398. }
  399. if err != nil {
  400. return err
  401. }
  402. _, err = fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n")
  403. if err != nil {
  404. return err
  405. }
  406. str, err = in.ReadString('\n')
  407. if err != nil {
  408. return err
  409. }
  410. _, err = fmt.Fprint(conn, "DATA\r\n")
  411. if err != nil {
  412. return err
  413. }
  414. str, err = in.ReadString('\n')
  415. if err != nil {
  416. return err
  417. }
  418. if body == "" {
  419. _, err = fmt.Fprint(conn, "Subject: Test subject\r\n")
  420. if err != nil {
  421. return err
  422. }
  423. _, err = fmt.Fprint(conn, "\r\n")
  424. if err != nil {
  425. return err
  426. }
  427. _, err = fmt.Fprint(conn, "A an email body\r\n")
  428. if err != nil {
  429. return err
  430. }
  431. _, err = fmt.Fprint(conn, ".\r\n")
  432. if err != nil {
  433. return err
  434. }
  435. } else {
  436. _, err = fmt.Fprint(conn, body)
  437. if err != nil {
  438. return err
  439. }
  440. _, err = fmt.Fprint(conn, ".\r\n")
  441. if err != nil {
  442. return err
  443. }
  444. }
  445. str, err = in.ReadString('\n')
  446. if err != nil {
  447. return err
  448. }
  449. _, err = fmt.Fprint(conn, "QUIT\r\n")
  450. if err != nil {
  451. return err
  452. }
  453. _ = str
  454. return nil
  455. }
  456. // Test hot config reload
  457. // Here we forgot to add FunkyLogger so backend will fail to init
  458. func TestReloadConfig(t *testing.T) {
  459. if err := os.Truncate("tests/testlog", 0); err != nil {
  460. t.Error(err)
  461. }
  462. d := Daemon{}
  463. if err := d.Start(); err != nil {
  464. t.Error(err)
  465. }
  466. defer d.Shutdown()
  467. cfg := AppConfig{
  468. LogFile: "tests/testlog",
  469. AllowedHosts: []string{"grr.la"},
  470. BackendConfig: backends.BackendConfig{
  471. "save_process": "HeadersParser|Debugger|FunkyLogger",
  472. "validate_process": "FunkyLogger",
  473. },
  474. }
  475. // Look mom, reloading the config without shutting down!
  476. if err := d.ReloadConfig(cfg); err != nil {
  477. t.Error(err)
  478. }
  479. }
  480. func TestPubSubAPI(t *testing.T) {
  481. if err := os.Truncate("tests/testlog", 0); err != nil {
  482. t.Error(err)
  483. }
  484. d := Daemon{Config: &AppConfig{LogFile: "tests/testlog"}}
  485. if err := d.Start(); err != nil {
  486. t.Error(err)
  487. }
  488. defer d.Shutdown()
  489. // new config
  490. cfg := AppConfig{
  491. PidFile: "tests/pidfilex.pid",
  492. LogFile: "tests/testlog",
  493. AllowedHosts: []string{"grr.la"},
  494. BackendConfig: backends.BackendConfig{
  495. "save_process": "HeadersParser|Debugger|FunkyLogger",
  496. "validate_process": "FunkyLogger",
  497. },
  498. }
  499. var i = 0
  500. pidEvHandler := func(c *AppConfig) {
  501. i++
  502. if i > 1 {
  503. t.Error("number > 1, it means d.Unsubscribe didn't work")
  504. }
  505. d.Logger.Info("number", i)
  506. }
  507. if err := d.Subscribe(EventConfigPidFile, pidEvHandler); err != nil {
  508. t.Error(err)
  509. }
  510. if err := d.ReloadConfig(cfg); err != nil {
  511. t.Error(err)
  512. }
  513. if err := d.Unsubscribe(EventConfigPidFile, pidEvHandler); err != nil {
  514. t.Error(err)
  515. }
  516. cfg.PidFile = "tests/pidfile2.pid"
  517. d.Publish(EventConfigPidFile, &cfg)
  518. if err := d.ReloadConfig(cfg); err != nil {
  519. t.Error(err)
  520. }
  521. b, err := ioutil.ReadFile("tests/testlog")
  522. if err != nil {
  523. t.Error("could not read logfile")
  524. return
  525. }
  526. // lets interrogate the log
  527. if strings.Index(string(b), "number1") < 0 {
  528. t.Error("it lools like d.ReloadConfig(cfg) did not fire EventConfigPidFile, pidEvHandler not called")
  529. }
  530. }
  531. func TestAPILog(t *testing.T) {
  532. if err := os.Truncate("tests/testlog", 0); err != nil {
  533. t.Error(err)
  534. }
  535. d := Daemon{}
  536. l := d.Log()
  537. l.Info("logtest1") // to stderr
  538. if l.GetLevel() != log.InfoLevel.String() {
  539. t.Error("Log level does not eq info, it is ", l.GetLevel())
  540. }
  541. d.Logger = nil
  542. d.Config = &AppConfig{LogFile: "tests/testlog"}
  543. l = d.Log()
  544. l.Info("logtest1") // to tests/testlog
  545. //
  546. l = d.Log()
  547. if l.GetLogDest() != "tests/testlog" {
  548. t.Error("log dest is not tests/testlog, it was ", l.GetLogDest())
  549. }
  550. b, err := ioutil.ReadFile("tests/testlog")
  551. if err != nil {
  552. t.Error("could not read logfile")
  553. return
  554. }
  555. // lets interrogate the log
  556. if strings.Index(string(b), "logtest1") < 0 {
  557. t.Error("hai was not found in the log, it should have been in tests/testlog")
  558. }
  559. }
  560. // Test the allowed_hosts config option with a single entry of ".", which will allow all hosts.
  561. func TestSkipAllowsHost(t *testing.T) {
  562. d := Daemon{}
  563. defer d.Shutdown()
  564. // setting the allowed hosts to a single entry with a dot will let any host through
  565. d.Config = &AppConfig{AllowedHosts: []string{"."}, LogFile: "off"}
  566. if err := d.Start(); err != nil {
  567. t.Error(err)
  568. }
  569. conn, err := net.Dial("tcp", d.Config.Servers[0].ListenInterface)
  570. if err != nil {
  571. t.Error(t)
  572. return
  573. }
  574. in := bufio.NewReader(conn)
  575. if _, err := fmt.Fprint(conn, "HELO test\r\n"); err != nil {
  576. t.Error(err)
  577. }
  578. if _, err := fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n"); err != nil {
  579. t.Error(err)
  580. }
  581. if _, err := in.ReadString('\n'); err != nil {
  582. t.Error(err)
  583. }
  584. if _, err := in.ReadString('\n'); err != nil {
  585. t.Error(err)
  586. }
  587. str, _ := in.ReadString('\n')
  588. if strings.Index(str, "250") != 0 {
  589. t.Error("expected 250 reply, got:", str)
  590. }
  591. }
  592. var customBackend2 = func() backends.Decorator {
  593. return func(p backends.Processor) backends.Processor {
  594. return backends.ProcessWith(
  595. func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
  596. if task == backends.TaskValidateRcpt {
  597. return p.Process(e, task)
  598. } else if task == backends.TaskSaveMail {
  599. backends.Log().Info("Another funky email!")
  600. err := errors.New("system shock")
  601. return backends.NewResult(response.Canned.FailReadErrorDataCmd, response.SP, err), err
  602. }
  603. return p.Process(e, task)
  604. })
  605. }
  606. }
  607. // Test a custom backend response
  608. func TestCustomBackendResult(t *testing.T) {
  609. if err := os.Truncate("tests/testlog", 0); err != nil {
  610. t.Error(err)
  611. }
  612. cfg := &AppConfig{
  613. LogFile: "tests/testlog",
  614. AllowedHosts: []string{"grr.la"},
  615. BackendConfig: backends.BackendConfig{
  616. "save_process": "HeadersParser|Debugger|Custom",
  617. "validate_process": "Custom",
  618. },
  619. }
  620. d := Daemon{Config: cfg}
  621. d.AddProcessor("Custom", customBackend2)
  622. if err := d.Start(); err != nil {
  623. t.Error(err)
  624. }
  625. // lets have a talk with the server
  626. if err := talkToServer("127.0.0.1:2525", ""); err != nil {
  627. t.Error(err)
  628. }
  629. d.Shutdown()
  630. b, err := ioutil.ReadFile("tests/testlog")
  631. if err != nil {
  632. t.Error("could not read logfile")
  633. return
  634. }
  635. // lets check for fingerprints
  636. if strings.Index(string(b), "451 4.3.0 Error") < 0 {
  637. t.Error("did not log: 451 4.3.0 Error")
  638. }
  639. if strings.Index(string(b), "system shock") < 0 {
  640. t.Error("did not log: system shock")
  641. }
  642. }
  643. func TestStreamProcessor(t *testing.T) {
  644. if err := os.Truncate("tests/testlog", 0); err != nil {
  645. t.Error(err)
  646. }
  647. cfg := &AppConfig{
  648. LogFile: "tests/testlog",
  649. AllowedHosts: []string{"grr.la"},
  650. BackendConfig: backends.BackendConfig{
  651. "save_process": "HeadersParser|Debugger",
  652. "stream_save_process": "Header|headersparser|compress|Decompress|debug",
  653. },
  654. }
  655. d := Daemon{Config: cfg}
  656. if err := d.Start(); err != nil {
  657. t.Error(err)
  658. }
  659. body := "Subject: Test subject\r\n" +
  660. //"\r\n" +
  661. "A an email body.\r\n" +
  662. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  663. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  664. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  665. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  666. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  667. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  668. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  669. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  670. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  671. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  672. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  673. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n"
  674. // lets have a talk with the server
  675. if err := talkToServer("127.0.0.1:2525", body); err != nil {
  676. t.Error(err)
  677. }
  678. d.Shutdown()
  679. b, err := ioutil.ReadFile("tests/testlog")
  680. if err != nil {
  681. t.Error("could not read logfile")
  682. return
  683. }
  684. // lets check for fingerprints
  685. if strings.Index(string(b), "Debug stream") < 0 {
  686. t.Error("did not log: Debug stream")
  687. }
  688. if strings.Index(string(b), "Error") != -1 {
  689. t.Error("There was an error", string(b))
  690. }
  691. }
  692. var mime0 = `MIME-Version: 1.0
  693. X-Mailer: MailBee.NET 8.0.4.428
  694. Subject: test
  695. subject
  696. To: [email protected]
  697. Content-Type: multipart/mixed;
  698. boundary="XXXXboundary text"
  699. --XXXXboundary text
  700. Content-Type: multipart/alternative;
  701. boundary="XXXXboundary text"
  702. --XXXXboundary text
  703. Content-Type: text/plain;
  704. charset="utf-8"
  705. Content-Transfer-Encoding: quoted-printable
  706. This is the body text of a sample message.
  707. --XXXXboundary text
  708. Content-Type: text/html;
  709. charset="utf-8"
  710. Content-Transfer-Encoding: quoted-printable
  711. <pre>This is the body text of a sample message.</pre>
  712. --XXXXboundary text
  713. Content-Type: text/plain;
  714. name="log_attachment.txt"
  715. Content-Disposition: attachment;
  716. filename="log_attachment.txt"
  717. Content-Transfer-Encoding: base64
  718. TUlNRS1WZXJzaW9uOiAxLjANClgtTWFpbGVyOiBNYWlsQmVlLk5FVCA4LjAuNC40MjgNClN1Ympl
  719. Y3Q6IHRlc3Qgc3ViamVjdA0KVG86IGtldmlubUBkYXRhbW90aW9uLmNvbQ0KQ29udGVudC1UeXBl
  720. OiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7DQoJYm91bmRhcnk9Ii0tLS09X05leHRQYXJ0XzAwMF9B
  721. RTZCXzcyNUUwOUFGLjg4QjdGOTM0Ig0KDQoNCi0tLS0tLT1fTmV4dFBhcnRfMDAwX0FFNkJfNzI1
  722. RTA5QUYuODhCN0Y5MzQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsNCgljaGFyc2V0PSJ1dGYt
  723. OCINCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KdGVzdCBi
  724. b2R5DQotLS0tLS09X05leHRQYXJ0XzAwMF9BRTZCXzcyNUUwOUFGLjg4QjdGOTM0DQpDb250ZW50
  725. LVR5cGU6IHRleHQvaHRtbDsNCgljaGFyc2V0PSJ1dGYtOCINCkNvbnRlbnQtVHJhbnNmZXItRW5j
  726. b2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KPHByZT50ZXN0IGJvZHk8L3ByZT4NCi0tLS0tLT1f
  727. TmV4dFBhcnRfMDAwX0FFNkJfNzI1RTA5QUYuODhCN0Y5MzQtLQ0K
  728. --XXXXboundary text--
  729. `
  730. var mime2 = `From: [email protected]
  731. Content-Type: multipart/mixed;
  732. boundary="----_=_NextPart_001_01CBE273.65A0E7AA"
  733. To: [email protected]
  734. This is a multi-part message in MIME format.
  735. ------_=_NextPart_001_01CBE273.65A0E7AA
  736. Content-Type: multipart/alternative;
  737. boundary="----_=_NextPart_002_01CBE273.65A0E7AA"
  738. ------_=_NextPart_002_01CBE273.65A0E7AA
  739. Content-Type: text/plain;
  740. charset="UTF-8"
  741. Content-Transfer-Encoding: base64
  742. [base64-content]
  743. ------_=_NextPart_002_01CBE273.65A0E7AA
  744. Content-Type: text/html;
  745. charset="UTF-8"
  746. Content-Transfer-Encoding: base64
  747. [base64-content]
  748. ------_=_NextPart_002_01CBE273.65A0E7AA--
  749. ------_=_NextPart_001_01CBE273.65A0E7AA
  750. Content-Type: message/rfc822
  751. Content-Transfer-Encoding: 7bit
  752. X-MimeOLE: Produced By Microsoft Exchange V6.5
  753. Content-class: urn:content-classes:message
  754. MIME-Version: 1.0
  755. Content-Type: multipart/mixed;
  756. boundary="----_=_NextPart_003_01CBE272.13692C80"
  757. From: [email protected]
  758. To: [email protected]
  759. This is a multi-part message in MIME format.
  760. ------_=_NextPart_003_01CBE272.13692C80
  761. Content-Type: multipart/alternative;
  762. boundary="----_=_NextPart_004_01CBE272.13692C80"
  763. ------_=_NextPart_004_01CBE272.13692C80
  764. Content-Type: text/plain;
  765. charset="iso-8859-1"
  766. Content-Transfer-Encoding: quoted-printable
  767. =20
  768. Viele Gr=FC=DFe
  769. ------_=_NextPart_004_01CBE272.13692C80
  770. Content-Type: text/html;
  771. charset="iso-8859-1"
  772. Content-Transfer-Encoding: quoted-printable
  773. <html>...</html>
  774. ------_=_NextPart_004_01CBE272.13692C80--
  775. ------_=_NextPart_003_01CBE272.13692C80
  776. Content-Type: application/x-zip-compressed;
  777. name="abc.zip"
  778. Content-Transfer-Encoding: base64
  779. Content-Disposition: attachment;
  780. filename="abc.zip"
  781. [base64-content]
  782. ------_=_NextPart_003_01CBE272.13692C80--
  783. ------_=_NextPart_001_01CBE273.65A0E7AA--
  784. `
  785. var mime3 = `From [email protected] Mon Feb 19 22:24:21 2001
  786. Received: from [137.154.210.66] by hotmail.com (3.2) with ESMTP id MHotMailBC5B58230039400431D5899AD24289FA0; Mon Feb 19 22:22:29 2001
  787. Received: from lancelot.cit.nepean.uws.edu.au (lancelot.cit.uws.edu.au [137.154.148.30])
  788. by day.uws.edu.au (8.11.1/8.11.1) with ESMTP id f1K6MN404936;
  789. Tue, 20 Feb 2001 17:22:24 +1100 (EST)
  790. Received: from hotmail.com (law2-f35.hotmail.com [216.32.181.35])
  791. by lancelot.cit.nepean.uws.edu.au (8.10.0.Beta10/8.10.0.Beta10) with ESMTP id f1K6MJb13619;
  792. Tue, 20 Feb 2001 17:22:19 +1100 (EST)
  793. Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC;
  794. Mon, 19 Feb 2001 22:21:44 -0800
  795. Received: from 203.54.221.89 by lw2fd.hotmail.msn.com with HTTP; Tue, 20 Feb 2001 06:21:44 GMT
  796. X-Originating-IP: [203.54.221.89]
  797. From: "lara devine" <[email protected]>
  798. To: [email protected], [email protected],
  799. [email protected], [email protected],
  800. [email protected], [email protected],
  801. [email protected], [email protected],
  802. [email protected]
  803. Subject: Fwd: Goldfish
  804. Date: Tue, 20 Feb 2001 06:21:44
  805. Mime-Version: 1.0
  806. Content-Type: text/plain; format=flowed
  807. Message-ID: <[email protected]>
  808. X-OriginalArrivalTime: 20 Feb 2001 06:21:44.0718 (UTC) FILETIME=[658BDAE0:01C09B05]
  809. >> >Two builders (Chris and James) are seated either side of a table in a
  810. > > >rough
  811. > > >pub when a well-dressed man enters, orders beer and sits on a stool at
  812. > > >the bar.
  813. > > >The two builders start to speculate about the occupation of the suit.
  814. > > >
  815. > > >Chris: - I reckon he's an accountant.
  816. > > >
  817. > > >James: - No way - he's a stockbroker.
  818. > > >
  819. > > >Chris: - He ain't no stockbroker! A stockbroker wouldn't come in here!
  820. > > >
  821. > > >The argument repeats itself for some time until the volume of beer gets
  822. > > >the better of Chris and he makes for the toilet. On entering the toilet
  823. > > >he
  824. > > >sees that the suit is standing at a urinal. Curiosity and the several
  825. > > >beers
  826. > > >get the better of the builder...
  827. > > >
  828. > > >Chris: - 'scuse me.... no offence meant, but me and me mate were
  829. > > wondering
  830. > > >
  831. > > > what you do for a living?
  832. > > >
  833. > > >Suit: - No offence taken! I'm a Logical Scientist by profession!
  834. > > >
  835. > > >Chris: - Oh! What's that then?
  836. > > >
  837. > > >Suit:- I'll try to explain by example... Do you have a goldfish at
  838. >home?
  839. > > >
  840. > > >Chris:- Er...mmm... well yeah, I do as it happens!
  841. > > >
  842. > > >Suit: - Well, it's logical to follow that you keep it in a bowl or in a
  843. > > >pond. Which is it?
  844. > > >
  845. > > >Chris: - It's in a pond!
  846. > > >
  847. > > >Suit: - Well then it's reasonable to suppose that you have a large
  848. > > >garden
  849. > > >then?
  850. > > >
  851. > > >Chris: - As it happens, yes I have got a big garden!
  852. > > >
  853. > > >Suit: - Well then it's logical to assume that in this town that if you
  854. > > >have a large garden that you have a large house?
  855. > > >
  856. > > >Chris: - As it happens I've got a five bedroom house... built it
  857. >myself!
  858. > > >
  859. > > >Suit: - Well given that you've built a five-bedroom house it is logical
  860. > > >to asume that you haven't built it just for yourself and that you are
  861. > > >quite
  862. > > >probably married?
  863. > > >
  864. > > >Chris: - Yes I am married, I live with my wife and three children!
  865. > > >
  866. > > >Suit: - Well then it is logical to assume that you are sexually active
  867. > > >with your wife on a regular basis?
  868. > > >
  869. > > >Chris:- Yep! Four nights a week!
  870. > > >
  871. > > >Suit: - Well then it is logical to suggest that you do not masturbate
  872. > > >very often?
  873. > > >
  874. > > >Chris: - Me? Never.
  875. > > >
  876. > > >Suit: - Well there you are! That's logical science at work!
  877. > > >
  878. > > >Chris:- How's that then?
  879. > > >
  880. > > >Suit: - Well from finding out that you had a goldfish, I've told you
  881. > > >about the size of garden you have, size of house, your family and your
  882. > > >sex
  883. > > >life!
  884. > > >
  885. > > >Chris: - I see! That's pretty impressive... thanks mate!
  886. > > >
  887. > > >Both leave the toilet and Chris returns to his mate.
  888. > > >
  889. > > >James: - I see the suit was in there. Did you ask him what he does?
  890. > > >
  891. > > >Chris: - Yep! He's a logical scientist!
  892. > > >
  893. > > >James: What's a logical Scientist?
  894. > > >
  895. > > >Chris: - I'll try and explain. Do you have a goldfish?
  896. > > >
  897. > > >James: - Nope.
  898. > > >
  899. > > >Chris: - Well then, you're a wanker.
  900. >
  901. _________________________________________________________________________
  902. Get Your Private, Free E-mail from MSN Hotmail at http://www.hotmail.com.
  903. `
  904. /*
  905. 1 0 166 1514
  906. 1.1 186 260 259
  907. 1.2 280 374 416
  908. 1.3 437 530 584
  909. 1.4 605 769 1514
  910. */
  911. func TestStreamMimeProcessor(t *testing.T) {
  912. if err := os.Truncate("tests/testlog", 0); err != nil {
  913. t.Error(err)
  914. }
  915. cfg := &AppConfig{
  916. LogFile: "tests/testlog",
  917. AllowedHosts: []string{"grr.la"},
  918. BackendConfig: backends.BackendConfig{
  919. "save_process": "HeadersParser|Debugger",
  920. "stream_save_process": "mimeanalyzer|headersparser|compress|Decompress|debug",
  921. },
  922. }
  923. d := Daemon{Config: cfg}
  924. if err := d.Start(); err != nil {
  925. t.Error(err)
  926. }
  927. go func() {
  928. time.Sleep(time.Second * 15)
  929. // for debugging deadlocks
  930. //pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
  931. //os.Exit(1)
  932. }()
  933. // change \n to \r\n
  934. mime0 = strings.Replace(mime2, "\n", "\r\n", -1)
  935. // lets have a talk with the server
  936. if err := talkToServer("127.0.0.1:2525", mime0); err != nil {
  937. t.Error(err)
  938. }
  939. d.Shutdown()
  940. b, err := ioutil.ReadFile("tests/testlog")
  941. if err != nil {
  942. t.Error("could not read logfile")
  943. return
  944. }
  945. // lets check for fingerprints
  946. if strings.Index(string(b), "Debug stream") < 0 {
  947. t.Error("did not log: Debug stream")
  948. }
  949. if strings.Index(string(b), "Error") != -1 {
  950. t.Error("There was an error", string(b))
  951. }
  952. }
  953. var email = `From: Al Gore <[email protected]>
  954. To: White House Transportation Coordinator <[email protected]>
  955. Subject: [Fwd: Map of Argentina with Description]
  956. MIME-Version: 1.0
  957. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; s=ncr424; d=reliancegeneral.co.in;
  958. h=List-Unsubscribe:MIME-Version:From:To:Reply-To:Date:Subject:Content-Type:Content-Transfer-Encoding:Message-ID; [email protected];
  959. bh=F4UQPGEkpmh54C7v3DL8mm2db1QhZU4gRHR1jDqffG8=;
  960. b=MVltcq6/I9b218a370fuNFLNinR9zQcdBSmzttFkZ7TvV2mOsGrzrwORT8PKYq4KNJNOLBahswXf
  961. GwaMjDKT/5TXzegdX/L3f/X4bMAEO1einn+nUkVGLK4zVQus+KGqm4oP7uVXjqp70PWXScyWWkbT
  962. 1PGUwRfPd/HTJG5IUqs=
  963. Content-Type: multipart/mixed;
  964. boundary="D7F------------D7FD5A0B8AB9C65CCDBFA872"
  965. This is a multi-part message in MIME format.
  966. --D7F------------D7FD5A0B8AB9C65CCDBFA872
  967. Content-Type: text/plain; charset=us-ascii
  968. Content-Transfer-Encoding: 7bit
  969. Fred,
  970. Fire up Air Force One! We're going South!
  971. Thanks,
  972. Al
  973. --D7F------------D7FD5A0B8AB9C65CCDBFA872
  974. Content-Type: message/rfc822
  975. Content-Transfer-Encoding: 7bit
  976. Content-Disposition: inline
  977. Return-Path: <[email protected]>
  978. Received: from mailhost.whitehouse.gov ([192.168.51.200])
  979. by heartbeat.whitehouse.gov (8.8.8/8.8.8) with ESMTP id SAA22453
  980. for <[email protected]>;
  981. Mon, 13 Aug 1998 l8:14:23 +1000
  982. Received: from the_big_box.whitehouse.gov ([192.168.51.50])
  983. by mailhost.whitehouse.gov (8.8.8/8.8.7) with ESMTP id RAA20366
  984. for [email protected]; Mon, 13 Aug 1998 17:42:41 +1000
  985. Date: Mon, 13 Aug 1998 17:42:41 +1000
  986. Message-Id: <[email protected]>
  987. From: Bill Clinton <[email protected]>
  988. To: A1 (The Enforcer) Gore <[email protected]>
  989. Subject: Map of Argentina with Description
  990. MIME-Version: 1.0
  991. Content-Type: multipart/mixed;
  992. boundary="DC8------------DC8638F443D87A7F0726DEF7"
  993. This is a multi-part message in MIME format.
  994. --DC8------------DC8638F443D87A7F0726DEF7
  995. Content-Type: text/plain; charset=us-ascii
  996. Content-Transfer-Encoding: 7bit
  997. Hi A1,
  998. I finally figured out this MIME thing. Pretty cool. I'll send you
  999. some sax music in .au files next week!
  1000. Anyway, the attached image is really too small to get a good look at
  1001. Argentina. Try this for a much better map:
  1002. http://www.1one1yp1anet.com/dest/sam/graphics/map-arg.htm
  1003. Then again, shouldn't the CIA have something like that?
  1004. Bill
  1005. --DC8------------DC8638F443D87A7F0726DEF7
  1006. Content-Type: image/gif; name="map_of_Argentina.gif"
  1007. Content-Transfer-Encoding: base64
  1008. Content-Disposition: inline; filename="map_of_Argentina.gif"
  1009. R01GOD1hJQA1AKIAAP/////78P/omn19fQAAAAAAAAAAAAAAACwAAAAAJQA1AAAD7Qi63P5w
  1010. wEmjBCLrnQnhYCgM1wh+pkgqqeC9XrutmBm7hAK3tP31gFcAiFKVQrGFR6kscnonTe7FAAad
  1011. GugmRu3CmiBt57fsVq3Y0VFKnpYdxPC6M7Ze4crnnHum4oN6LFJ1bn5NXTN7OF5fQkN5WYow
  1012. BEN2dkGQGWJtSzqGTICJgnQuTJN/WJsojad9qXMuhIWdjXKjY4tenjo6tjVssk2gaWq3uGNX
  1013. U6ZGxseyk8SasGw3J9GRzdTQky1iHNvcPNNI4TLeKdfMvy0vMqLrItvuxfDW8ubjueDtJufz
  1014. 7itICBxISKDBgwgTKjyYAAA7
  1015. --DC8------------DC8638F443D87A7F0726DEF7--
  1016. --D7F------------D7FD5A0B8AB9C65CCDBFA872--
  1017. `
  1018. func TestStreamChunkSaver(t *testing.T) {
  1019. if err := os.Truncate("tests/testlog", 0); err != nil {
  1020. t.Error(err)
  1021. }
  1022. go func() {
  1023. time.Sleep(time.Second * 15)
  1024. // for debugging deadlocks
  1025. //pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
  1026. //os.Exit(1)
  1027. }()
  1028. cfg := &AppConfig{
  1029. LogFile: "tests/testlog",
  1030. AllowedHosts: []string{"grr.la"},
  1031. BackendConfig: backends.BackendConfig{
  1032. "stream_save_process": "mimeanalyzer|chunksaver",
  1033. "chunksaver_chunk_size": 1024 * 32,
  1034. "stream_buffer_size": 1024 * 16,
  1035. },
  1036. }
  1037. d := Daemon{Config: cfg}
  1038. if err := d.Start(); err != nil {
  1039. t.Error(err)
  1040. }
  1041. // change \n to \r\n
  1042. email = strings.Replace(email, "\n", "\r\n", -1)
  1043. // lets have a talk with the server
  1044. if err := talkToServer("127.0.0.1:2525", email); err != nil {
  1045. t.Error(err)
  1046. }
  1047. time.Sleep(time.Second * 1)
  1048. d.Shutdown()
  1049. b, err := ioutil.ReadFile("tests/testlog")
  1050. if err != nil {
  1051. t.Error("could not read logfile")
  1052. return
  1053. }
  1054. fmt.Println(string(b))
  1055. // lets check for fingerprints
  1056. if strings.Index(string(b), "Debug stream") < 0 {
  1057. // t.Error("did not log: Debug stream")
  1058. }
  1059. }