123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- // build gofuzz
- package guerrilla
- import (
- "bytes"
- "fmt"
- "github.com/flashmob/go-guerrilla/backends"
- "github.com/flashmob/go-guerrilla/log"
- "github.com/flashmob/go-guerrilla/mail"
- "github.com/flashmob/go-guerrilla/mocks"
- "io"
- "sync"
- "time"
- )
- var logOff log.Logger
- var fuzzServer *server
- var envelopePool *mail.Pool
- func init() {
- sc := getFuzzServerConfig()
- logOff, _ = log.GetLogger(sc.LogFile, log.ErrorLevel.String())
- fuzzServer = getFuzzServer(sc)
- isFuzzDebug = false
- envelopePool = mail.NewPool(sc.MaxClients)
- }
- func getFuzzServerConfig() *ServerConfig {
- sc := &ServerConfig{
- IsEnabled: true, //
- Hostname: "fuzzme.test.com",
- MaxSize: 1024, // smtp message max size
- TLS: ServerTLSConfig{
- PrivateKeyFile: "./tests/mail.guerrillamail.com.key.pem",
- PublicKeyFile: "./tests/mail.guerrillamail.com.cert.pem",
- StartTLSOn: true,
- AlwaysOn: false,
- },
- Timeout: 5,
- ListenInterface: "127.0.0.1:2529",
- MaxClients: 3000,
- LogFile: "off",
- }
- return sc
- }
- // getMockServer gets a new server using sc. Server will be using a using the dummy backend
- // RCP TO command only allows test.com host
- func getFuzzServer(sc *ServerConfig) *server {
- var logOpenError error
- var mainlog log.Logger
- mainlog, logOpenError = log.GetLogger(sc.LogFile, log.ErrorLevel.String())
- if logOpenError != nil {
- mainlog.WithError(logOpenError).Errorf("Failed creating a logger for mock conn [%s]", sc.ListenInterface)
- }
- backend, err := backends.New(backends.BackendConfig{
- "log_received_mails": true, "save_process_": "HeadersParser|Header|Debugger"}, mainlog)
- if err != nil {
- //t.Error("new dummy backend failed because:", err)
- }
- backend.Start()
- server, err := newServer(sc, backend, mainlog)
- if err != nil {
- //t.Error("new server failed because:", err)
- } else {
- server.setAllowedHosts([]string{"test.com"})
- }
- return server
- }
- var mockClient *client
- var isFuzzDebug bool
- // Fuzz passes the data to the mock connection
- // Data is random input generated by go-fuzz, note that in most cases it is invalid.
- // The function must return 1 if the fuzzer should increase priority of the given input during subsequent
- // fuzzing (for example, the input is lexically correct and was parsed successfully); -1 if the input must
- // not be added to corpus even if gives new coverage; and 0 otherwise
- func Fuzz(data []byte) int {
- var wg sync.WaitGroup
- // grab a new mocked tcp connection, it consists of two pipes (io.Pipe)
- conn := mocks.NewConn()
- // Get a client from the pool
- poolable, err := fuzzServer.clientPool.Borrow(conn.Server, 1, logOff, envelopePool)
- if c, ok := poolable.(*client); !ok {
- panic("cannot borrow from pool")
- } else {
- mockClient = c
- }
- defer func() {
- conn.Close()
- // wait for handleClient to exit
- wg.Wait()
- // return to the pool
- fuzzServer.clientPool.Return(mockClient)
- }()
- wg.Add(1)
- go func() {
- fuzzServer.handleClient(mockClient)
- wg.Done()
- }()
- // read in the greeting
- in := newSMTPBufferedReader(conn.Client)
- s, _ := in.ReadString('\n')
- if isFuzzDebug {
- fmt.Println("Read", s)
- }
- // Feed the connection with fuzz data (we are the _client_ end of the connection)
- if _, err = io.Copy(conn.Client, bytes.NewReader(data)); err != nil {
- fmt.Println(err)
- return 1
- }
- // allow handleClient to process
- time.Sleep(time.Millisecond + 10)
- if mockClient.bufout.Buffered() == 0 {
- // nothing to read - no complete commands sent?
- return 1
- }
- var e error
- var z string
- for ; e == nil; z, e = in.ReadString('\n') {
- fmt.Println("Read", z, mockClient.bufout.Buffered())
- if mockClient.bufout.Buffered() == 0 {
- break
- }
- }
- return 1
- }
|