fuzz.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // build gofuzz
  2. package guerrilla
  3. import (
  4. "bytes"
  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/mocks"
  10. "io"
  11. "sync"
  12. "time"
  13. )
  14. var logOff log.Logger
  15. var fuzzServer *server
  16. var envelopePool *mail.Pool
  17. func init() {
  18. sc := getFuzzServerConfig()
  19. logOff, _ = log.GetLogger(sc.LogFile, log.ErrorLevel.String())
  20. fuzzServer = getFuzzServer(sc)
  21. isFuzzDebug = false
  22. envelopePool = mail.NewPool(sc.MaxClients)
  23. }
  24. func getFuzzServerConfig() *ServerConfig {
  25. sc := &ServerConfig{
  26. IsEnabled: true, //
  27. Hostname: "fuzzme.test.com",
  28. MaxSize: 1024, // smtp message max size
  29. TLS: ServerTLSConfig{
  30. PrivateKeyFile: "./tests/mail.guerrillamail.com.key.pem",
  31. PublicKeyFile: "./tests/mail.guerrillamail.com.cert.pem",
  32. StartTLSOn: true,
  33. AlwaysOn: false,
  34. },
  35. Timeout: 5,
  36. ListenInterface: "127.0.0.1:2529",
  37. MaxClients: 3000,
  38. LogFile: "off",
  39. }
  40. return sc
  41. }
  42. // getMockServer gets a new server using sc. Server will be using a using the dummy backend
  43. // RCP TO command only allows test.com host
  44. func getFuzzServer(sc *ServerConfig) *server {
  45. var logOpenError error
  46. var mainlog log.Logger
  47. mainlog, logOpenError = log.GetLogger(sc.LogFile, log.ErrorLevel.String())
  48. if logOpenError != nil {
  49. mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
  50. }
  51. backend, err := backends.New(backends.BackendConfig{
  52. "log_received_mails": true, "save_process_": "HeadersParser|Header|Debugger"}, mainlog)
  53. if err != nil {
  54. //t.Error("new dummy backend failed because:", err)
  55. }
  56. backend.Start()
  57. server, err := newServer(sc, backend, mainlog)
  58. if err != nil {
  59. //t.Error("new server failed because:", err)
  60. } else {
  61. server.setAllowedHosts([]string{"test.com"})
  62. }
  63. return server
  64. }
  65. var mockClient *client
  66. var isFuzzDebug bool
  67. // Fuzz passes the data to the mock connection
  68. // Data is random input generated by go-fuzz, note that in most cases it is invalid.
  69. // The function must return 1 if the fuzzer should increase priority of the given input during subsequent
  70. // fuzzing (for example, the input is lexically correct and was parsed successfully); -1 if the input must
  71. // not be added to corpus even if gives new coverage; and 0 otherwise
  72. func Fuzz(data []byte) int {
  73. var wg sync.WaitGroup
  74. // grab a new mocked tcp connection, it consists of two pipes (io.Pipe)
  75. conn := mocks.NewConn()
  76. // Get a client from the pool
  77. poolable, err := fuzzServer.clientPool.Borrow(conn.Server, 1, logOff, envelopePool)
  78. if c, ok := poolable.(*client); !ok {
  79. panic("cannot borrow from pool")
  80. } else {
  81. mockClient = c
  82. }
  83. defer func() {
  84. conn.Close()
  85. // wait for handleClient to exit
  86. wg.Wait()
  87. // return to the pool
  88. fuzzServer.clientPool.Return(mockClient)
  89. }()
  90. wg.Add(1)
  91. go func() {
  92. fuzzServer.handleClient(mockClient)
  93. wg.Done()
  94. }()
  95. // read in the greeting
  96. in := newSMTPBufferedReader(conn.Client)
  97. s, _ := in.ReadString('\n')
  98. if isFuzzDebug {
  99. fmt.Println("Read", s)
  100. }
  101. // Feed the connection with fuzz data (we are the _client_ end of the connection)
  102. if _, err = io.Copy(conn.Client, bytes.NewReader(data)); err != nil {
  103. fmt.Println(err)
  104. return 1
  105. }
  106. // allow handleClient to process
  107. time.Sleep(time.Millisecond + 10)
  108. if mockClient.bufout.Buffered() == 0 {
  109. // nothing to read - no complete commands sent?
  110. return 1
  111. }
  112. var e error
  113. var z string
  114. for ; e == nil; z, e = in.ReadString('\n') {
  115. fmt.Println("Read", z, mockClient.bufout.Buffered())
  116. if mockClient.bufout.Buffered() == 0 {
  117. break
  118. }
  119. }
  120. return 1
  121. }