fuzz.go 3.5 KB

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