api_test.go 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  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\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. _ = str
  450. return nil
  451. }
  452. // Test hot config reload
  453. // Here we forgot to add FunkyLogger so backend will fail to init
  454. func TestReloadConfig(t *testing.T) {
  455. if err := os.Truncate("tests/testlog", 0); err != nil {
  456. t.Error(err)
  457. }
  458. d := Daemon{}
  459. if err := d.Start(); err != nil {
  460. t.Error(err)
  461. }
  462. defer d.Shutdown()
  463. cfg := AppConfig{
  464. LogFile: "tests/testlog",
  465. AllowedHosts: []string{"grr.la"},
  466. BackendConfig: backends.BackendConfig{
  467. "save_process": "HeadersParser|Debugger|FunkyLogger",
  468. "validate_process": "FunkyLogger",
  469. },
  470. }
  471. // Look mom, reloading the config without shutting down!
  472. if err := d.ReloadConfig(cfg); err != nil {
  473. t.Error(err)
  474. }
  475. }
  476. func TestPubSubAPI(t *testing.T) {
  477. if err := os.Truncate("tests/testlog", 0); err != nil {
  478. t.Error(err)
  479. }
  480. d := Daemon{Config: &AppConfig{LogFile: "tests/testlog"}}
  481. if err := d.Start(); err != nil {
  482. t.Error(err)
  483. }
  484. defer d.Shutdown()
  485. // new config
  486. cfg := AppConfig{
  487. PidFile: "tests/pidfilex.pid",
  488. LogFile: "tests/testlog",
  489. AllowedHosts: []string{"grr.la"},
  490. BackendConfig: backends.BackendConfig{
  491. "save_process": "HeadersParser|Debugger|FunkyLogger",
  492. "validate_process": "FunkyLogger",
  493. },
  494. }
  495. var i = 0
  496. pidEvHandler := func(c *AppConfig) {
  497. i++
  498. if i > 1 {
  499. t.Error("number > 1, it means d.Unsubscribe didn't work")
  500. }
  501. d.Logger.Info("number", i)
  502. }
  503. if err := d.Subscribe(EventConfigPidFile, pidEvHandler); err != nil {
  504. t.Error(err)
  505. }
  506. if err := d.ReloadConfig(cfg); err != nil {
  507. t.Error(err)
  508. }
  509. if err := d.Unsubscribe(EventConfigPidFile, pidEvHandler); err != nil {
  510. t.Error(err)
  511. }
  512. cfg.PidFile = "tests/pidfile2.pid"
  513. d.Publish(EventConfigPidFile, &cfg)
  514. if err := d.ReloadConfig(cfg); err != nil {
  515. t.Error(err)
  516. }
  517. b, err := ioutil.ReadFile("tests/testlog")
  518. if err != nil {
  519. t.Error("could not read logfile")
  520. return
  521. }
  522. // lets interrogate the log
  523. if strings.Index(string(b), "number1") < 0 {
  524. t.Error("it lools like d.ReloadConfig(cfg) did not fire EventConfigPidFile, pidEvHandler not called")
  525. }
  526. }
  527. func TestAPILog(t *testing.T) {
  528. if err := os.Truncate("tests/testlog", 0); err != nil {
  529. t.Error(err)
  530. }
  531. d := Daemon{}
  532. l := d.Log()
  533. l.Info("logtest1") // to stderr
  534. if l.GetLevel() != log.InfoLevel.String() {
  535. t.Error("Log level does not eq info, it is ", l.GetLevel())
  536. }
  537. d.Logger = nil
  538. d.Config = &AppConfig{LogFile: "tests/testlog"}
  539. l = d.Log()
  540. l.Info("logtest1") // to tests/testlog
  541. //
  542. l = d.Log()
  543. if l.GetLogDest() != "tests/testlog" {
  544. t.Error("log dest is not tests/testlog, it was ", l.GetLogDest())
  545. }
  546. b, err := ioutil.ReadFile("tests/testlog")
  547. if err != nil {
  548. t.Error("could not read logfile")
  549. return
  550. }
  551. // lets interrogate the log
  552. if strings.Index(string(b), "logtest1") < 0 {
  553. t.Error("hai was not found in the log, it should have been in tests/testlog")
  554. }
  555. }
  556. // Test the allowed_hosts config option with a single entry of ".", which will allow all hosts.
  557. func TestSkipAllowsHost(t *testing.T) {
  558. d := Daemon{}
  559. defer d.Shutdown()
  560. // setting the allowed hosts to a single entry with a dot will let any host through
  561. d.Config = &AppConfig{AllowedHosts: []string{"."}, LogFile: "off"}
  562. if err := d.Start(); err != nil {
  563. t.Error(err)
  564. }
  565. conn, err := net.Dial("tcp", d.Config.Servers[0].ListenInterface)
  566. if err != nil {
  567. t.Error(t)
  568. return
  569. }
  570. in := bufio.NewReader(conn)
  571. if _, err := fmt.Fprint(conn, "HELO test\r\n"); err != nil {
  572. t.Error(err)
  573. }
  574. if _, err := fmt.Fprint(conn, "RCPT TO:<[email protected]>\r\n"); err != nil {
  575. t.Error(err)
  576. }
  577. if _, err := in.ReadString('\n'); err != nil {
  578. t.Error(err)
  579. }
  580. if _, err := in.ReadString('\n'); err != nil {
  581. t.Error(err)
  582. }
  583. str, _ := in.ReadString('\n')
  584. if strings.Index(str, "250") != 0 {
  585. t.Error("expected 250 reply, got:", str)
  586. }
  587. }
  588. var customBackend2 = func() backends.Decorator {
  589. return func(p backends.Processor) backends.Processor {
  590. return backends.ProcessWith(
  591. func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
  592. if task == backends.TaskValidateRcpt {
  593. return p.Process(e, task)
  594. } else if task == backends.TaskSaveMail {
  595. backends.Log().Info("Another funky email!")
  596. err := errors.New("system shock")
  597. return backends.NewResult(response.Canned.FailReadErrorDataCmd, response.SP, err), err
  598. }
  599. return p.Process(e, task)
  600. })
  601. }
  602. }
  603. // Test a custom backend response
  604. func TestCustomBackendResult(t *testing.T) {
  605. if err := os.Truncate("tests/testlog", 0); err != nil {
  606. t.Error(err)
  607. }
  608. cfg := &AppConfig{
  609. LogFile: "tests/testlog",
  610. AllowedHosts: []string{"grr.la"},
  611. BackendConfig: backends.BackendConfig{
  612. "save_process": "HeadersParser|Debugger|Custom",
  613. "validate_process": "Custom",
  614. },
  615. }
  616. d := Daemon{Config: cfg}
  617. d.AddProcessor("Custom", customBackend2)
  618. if err := d.Start(); err != nil {
  619. t.Error(err)
  620. }
  621. // lets have a talk with the server
  622. if err := talkToServer("127.0.0.1:2525", ""); err != nil {
  623. t.Error(err)
  624. }
  625. d.Shutdown()
  626. b, err := ioutil.ReadFile("tests/testlog")
  627. if err != nil {
  628. t.Error("could not read logfile")
  629. return
  630. }
  631. // lets check for fingerprints
  632. if strings.Index(string(b), "451 4.3.0 Error") < 0 {
  633. t.Error("did not log: 451 4.3.0 Error")
  634. }
  635. if strings.Index(string(b), "system shock") < 0 {
  636. t.Error("did not log: system shock")
  637. }
  638. }
  639. func TestStreamProcessor(t *testing.T) {
  640. if err := os.Truncate("tests/testlog", 0); err != nil {
  641. t.Error(err)
  642. }
  643. cfg := &AppConfig{
  644. LogFile: "tests/testlog",
  645. AllowedHosts: []string{"grr.la"},
  646. BackendConfig: backends.BackendConfig{
  647. "save_process": "HeadersParser|Debugger",
  648. "stream_save_process": "Header|headersparser|compress|Decompress|debug",
  649. },
  650. }
  651. d := Daemon{Config: cfg}
  652. if err := d.Start(); err != nil {
  653. t.Error(err)
  654. }
  655. body := "Subject: Test subject\r\n" +
  656. //"\r\n" +
  657. "A an email body.\r\n" +
  658. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  659. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  660. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\r\n" +
  661. "Header|headersparser|compress|Decompress|debug Header|headersparser|compress|Decompress|debug.\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. // lets have a talk with the server
  671. if err := talkToServer("127.0.0.1:2525", body); err != nil {
  672. t.Error(err)
  673. }
  674. d.Shutdown()
  675. b, err := ioutil.ReadFile("tests/testlog")
  676. if err != nil {
  677. t.Error("could not read logfile")
  678. return
  679. }
  680. // lets check for fingerprints
  681. if strings.Index(string(b), "Debug stream") < 0 {
  682. t.Error("did not log: Debug stream")
  683. }
  684. if strings.Index(string(b), "Error") != -1 {
  685. t.Error("There was an error", string(b))
  686. }
  687. }
  688. var mime = `MIME-Version: 1.0
  689. X-Mailer: MailBee.NET 8.0.4.428
  690. Subject: test
  691. subject
  692. To: [email protected]
  693. Content-Type: multipart/mixed;
  694. boundary="XXXXboundary text"
  695. --XXXXboundary text
  696. Content-Type: multipart/alternative;
  697. boundary="XXXXboundary text"
  698. --XXXXboundary text
  699. Content-Type: text/plain;
  700. charset="utf-8"
  701. Content-Transfer-Encoding: quoted-printable
  702. This is the body text of a sample message.
  703. --XXXXboundary text
  704. Content-Type: text/html;
  705. charset="utf-8"
  706. Content-Transfer-Encoding: quoted-printable
  707. <pre>This is the body text of a sample message.</pre>
  708. --XXXXboundary text
  709. Content-Type: text/plain;
  710. name="log_attachment.txt"
  711. Content-Disposition: attachment;
  712. filename="log_attachment.txt"
  713. Content-Transfer-Encoding: base64
  714. TUlNRS1WZXJzaW9uOiAxLjANClgtTWFpbGVyOiBNYWlsQmVlLk5FVCA4LjAuNC40MjgNClN1Ympl
  715. Y3Q6IHRlc3Qgc3ViamVjdA0KVG86IGtldmlubUBkYXRhbW90aW9uLmNvbQ0KQ29udGVudC1UeXBl
  716. OiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7DQoJYm91bmRhcnk9Ii0tLS09X05leHRQYXJ0XzAwMF9B
  717. RTZCXzcyNUUwOUFGLjg4QjdGOTM0Ig0KDQoNCi0tLS0tLT1fTmV4dFBhcnRfMDAwX0FFNkJfNzI1
  718. RTA5QUYuODhCN0Y5MzQNCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsNCgljaGFyc2V0PSJ1dGYt
  719. OCINCkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KdGVzdCBi
  720. b2R5DQotLS0tLS09X05leHRQYXJ0XzAwMF9BRTZCXzcyNUUwOUFGLjg4QjdGOTM0DQpDb250ZW50
  721. LVR5cGU6IHRleHQvaHRtbDsNCgljaGFyc2V0PSJ1dGYtOCINCkNvbnRlbnQtVHJhbnNmZXItRW5j
  722. b2Rpbmc6IHF1b3RlZC1wcmludGFibGUNCg0KPHByZT50ZXN0IGJvZHk8L3ByZT4NCi0tLS0tLT1f
  723. TmV4dFBhcnRfMDAwX0FFNkJfNzI1RTA5QUYuODhCN0Y5MzQtLQ0K
  724. --XXXXboundary text--
  725. `
  726. var mime2 = `From: [email protected]
  727. Content-Type: multipart/mixed;
  728. boundary="----_=_NextPart_001_01CBE273.65A0E7AA"
  729. To: [email protected]
  730. This is a multi-part message in MIME format.
  731. ------_=_NextPart_001_01CBE273.65A0E7AA
  732. Content-Type: multipart/alternative;
  733. boundary="----_=_NextPart_002_01CBE273.65A0E7AA"
  734. ------_=_NextPart_002_01CBE273.65A0E7AA
  735. Content-Type: text/plain;
  736. charset="UTF-8"
  737. Content-Transfer-Encoding: base64
  738. [base64-content]
  739. ------_=_NextPart_002_01CBE273.65A0E7AA
  740. Content-Type: text/html;
  741. charset="UTF-8"
  742. Content-Transfer-Encoding: base64
  743. [base64-content]
  744. ------_=_NextPart_002_01CBE273.65A0E7AA--
  745. ------_=_NextPart_001_01CBE273.65A0E7AA
  746. Content-Type: message/rfc822
  747. Content-Transfer-Encoding: 7bit
  748. X-MimeOLE: Produced By Microsoft Exchange V6.5
  749. Content-class: urn:content-classes:message
  750. MIME-Version: 1.0
  751. Content-Type: multipart/mixed;
  752. boundary="----_=_NextPart_003_01CBE272.13692C80"
  753. From: [email protected]
  754. To: [email protected]
  755. This is a multi-part message in MIME format.
  756. ------_=_NextPart_003_01CBE272.13692C80
  757. Content-Type: multipart/alternative;
  758. boundary="----_=_NextPart_004_01CBE272.13692C80"
  759. ------_=_NextPart_004_01CBE272.13692C80
  760. Content-Type: text/plain;
  761. charset="iso-8859-1"
  762. Content-Transfer-Encoding: quoted-printable
  763. =20
  764. Viele Gr=FC=DFe
  765. ------_=_NextPart_004_01CBE272.13692C80
  766. Content-Type: text/html;
  767. charset="iso-8859-1"
  768. Content-Transfer-Encoding: quoted-printable
  769. <html>...</html>
  770. ------_=_NextPart_004_01CBE272.13692C80--
  771. ------_=_NextPart_003_01CBE272.13692C80
  772. Content-Type: application/x-zip-compressed;
  773. name="abc.zip"
  774. Content-Transfer-Encoding: base64
  775. Content-Disposition: attachment;
  776. filename="abc.zip"
  777. [base64-content]
  778. ------_=_NextPart_003_01CBE272.13692C80--
  779. ------_=_NextPart_001_01CBE273.65A0E7AA--
  780. `
  781. var mime3 = `From [email protected] Mon Feb 19 22:24:21 2001
  782. Received: from [137.154.210.66] by hotmail.com (3.2) with ESMTP id MHotMailBC5B58230039400431D5899AD24289FA0; Mon Feb 19 22:22:29 2001
  783. Received: from lancelot.cit.nepean.uws.edu.au (lancelot.cit.uws.edu.au [137.154.148.30])
  784. by day.uws.edu.au (8.11.1/8.11.1) with ESMTP id f1K6MN404936;
  785. Tue, 20 Feb 2001 17:22:24 +1100 (EST)
  786. Received: from hotmail.com (law2-f35.hotmail.com [216.32.181.35])
  787. by lancelot.cit.nepean.uws.edu.au (8.10.0.Beta10/8.10.0.Beta10) with ESMTP id f1K6MJb13619;
  788. Tue, 20 Feb 2001 17:22:19 +1100 (EST)
  789. Received: from mail pickup service by hotmail.com with Microsoft SMTPSVC;
  790. Mon, 19 Feb 2001 22:21:44 -0800
  791. Received: from 203.54.221.89 by lw2fd.hotmail.msn.com with HTTP; Tue, 20 Feb 2001 06:21:44 GMT
  792. X-Originating-IP: [203.54.221.89]
  793. From: "lara devine" <[email protected]>
  794. To: [email protected], [email protected],
  795. [email protected], [email protected],
  796. [email protected], [email protected],
  797. [email protected], [email protected],
  798. [email protected]
  799. Subject: Fwd: Goldfish
  800. Date: Tue, 20 Feb 2001 06:21:44
  801. Mime-Version: 1.0
  802. Content-Type: text/plain; format=flowed
  803. Message-ID: <[email protected]>
  804. X-OriginalArrivalTime: 20 Feb 2001 06:21:44.0718 (UTC) FILETIME=[658BDAE0:01C09B05]
  805. >> >Two builders (Chris and James) are seated either side of a table in a
  806. > > >rough
  807. > > >pub when a well-dressed man enters, orders beer and sits on a stool at
  808. > > >the bar.
  809. > > >The two builders start to speculate about the occupation of the suit.
  810. > > >
  811. > > >Chris: - I reckon he's an accountant.
  812. > > >
  813. > > >James: - No way - he's a stockbroker.
  814. > > >
  815. > > >Chris: - He ain't no stockbroker! A stockbroker wouldn't come in here!
  816. > > >
  817. > > >The argument repeats itself for some time until the volume of beer gets
  818. > > >the better of Chris and he makes for the toilet. On entering the toilet
  819. > > >he
  820. > > >sees that the suit is standing at a urinal. Curiosity and the several
  821. > > >beers
  822. > > >get the better of the builder...
  823. > > >
  824. > > >Chris: - 'scuse me.... no offence meant, but me and me mate were
  825. > > wondering
  826. > > >
  827. > > > what you do for a living?
  828. > > >
  829. > > >Suit: - No offence taken! I'm a Logical Scientist by profession!
  830. > > >
  831. > > >Chris: - Oh! What's that then?
  832. > > >
  833. > > >Suit:- I'll try to explain by example... Do you have a goldfish at
  834. >home?
  835. > > >
  836. > > >Chris:- Er...mmm... well yeah, I do as it happens!
  837. > > >
  838. > > >Suit: - Well, it's logical to follow that you keep it in a bowl or in a
  839. > > >pond. Which is it?
  840. > > >
  841. > > >Chris: - It's in a pond!
  842. > > >
  843. > > >Suit: - Well then it's reasonable to suppose that you have a large
  844. > > >garden
  845. > > >then?
  846. > > >
  847. > > >Chris: - As it happens, yes I have got a big garden!
  848. > > >
  849. > > >Suit: - Well then it's logical to assume that in this town that if you
  850. > > >have a large garden that you have a large house?
  851. > > >
  852. > > >Chris: - As it happens I've got a five bedroom house... built it
  853. >myself!
  854. > > >
  855. > > >Suit: - Well given that you've built a five-bedroom house it is logical
  856. > > >to asume that you haven't built it just for yourself and that you are
  857. > > >quite
  858. > > >probably married?
  859. > > >
  860. > > >Chris: - Yes I am married, I live with my wife and three children!
  861. > > >
  862. > > >Suit: - Well then it is logical to assume that you are sexually active
  863. > > >with your wife on a regular basis?
  864. > > >
  865. > > >Chris:- Yep! Four nights a week!
  866. > > >
  867. > > >Suit: - Well then it is logical to suggest that you do not masturbate
  868. > > >very often?
  869. > > >
  870. > > >Chris: - Me? Never.
  871. > > >
  872. > > >Suit: - Well there you are! That's logical science at work!
  873. > > >
  874. > > >Chris:- How's that then?
  875. > > >
  876. > > >Suit: - Well from finding out that you had a goldfish, I've told you
  877. > > >about the size of garden you have, size of house, your family and your
  878. > > >sex
  879. > > >life!
  880. > > >
  881. > > >Chris: - I see! That's pretty impressive... thanks mate!
  882. > > >
  883. > > >Both leave the toilet and Chris returns to his mate.
  884. > > >
  885. > > >James: - I see the suit was in there. Did you ask him what he does?
  886. > > >
  887. > > >Chris: - Yep! He's a logical scientist!
  888. > > >
  889. > > >James: What's a logical Scientist?
  890. > > >
  891. > > >Chris: - I'll try and explain. Do you have a goldfish?
  892. > > >
  893. > > >James: - Nope.
  894. > > >
  895. > > >Chris: - Well then, you're a wanker.
  896. >
  897. _________________________________________________________________________
  898. Get Your Private, Free E-mail from MSN Hotmail at http://www.hotmail.com.
  899. `
  900. /*
  901. 1 0 166 1514
  902. 1.1 186 260 259
  903. 1.2 280 374 416
  904. 1.3 437 530 584
  905. 1.4 605 769 1514
  906. */
  907. func TestStreamMimeProcessor(t *testing.T) {
  908. if err := os.Truncate("tests/testlog", 0); err != nil {
  909. t.Error(err)
  910. }
  911. cfg := &AppConfig{
  912. LogFile: "tests/testlog",
  913. AllowedHosts: []string{"grr.la"},
  914. BackendConfig: backends.BackendConfig{
  915. "save_process": "HeadersParser|Debugger",
  916. "stream_save_process": "mimeanalyzer|headersparser|compress|Decompress|debug",
  917. },
  918. }
  919. d := Daemon{Config: cfg}
  920. if err := d.Start(); err != nil {
  921. t.Error(err)
  922. }
  923. go func() {
  924. time.Sleep(time.Second * 15)
  925. //panic("here")
  926. // *moo = *moo + 6
  927. // for debugging deadlocks
  928. //pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
  929. //os.Exit(1)
  930. }()
  931. // change \n to \r\n
  932. mime = strings.Replace(mime2, "\n", "\r\n", -1)
  933. // lets have a talk with the server
  934. if err := talkToServer("127.0.0.1:2525", mime); err != nil {
  935. t.Error(err)
  936. }
  937. d.Shutdown()
  938. b, err := ioutil.ReadFile("tests/testlog")
  939. if err != nil {
  940. t.Error("could not read logfile")
  941. return
  942. }
  943. // lets check for fingerprints
  944. if strings.Index(string(b), "Debug stream") < 0 {
  945. t.Error("did not log: Debug stream")
  946. }
  947. if strings.Index(string(b), "Error") != -1 {
  948. t.Error("There was an error", string(b))
  949. }
  950. }