14	"github.com/mjl-/mox/imapclient"
 
15	"github.com/mjl-/mox/mlog"
 
16	"github.com/mjl-/mox/mox-"
 
17	"github.com/mjl-/mox/store"
 
20// Fuzz the server. For each fuzz string, we set up servers in various connection states, and write the string as command.
 
21func FuzzServer(f *testing.F) {
 
23		fmt.Sprintf("authenticate plain %s", base64.StdEncoding.EncodeToString([]byte("\u0000mjl@mox.example\u0000testtest"))),
 
41		"rename tmpbox ntmpbox",
 
43		"status inbox (uidnext messages uidvalidity deleted size unseen recent)",
 
44		"append inbox (\\seen) {2+}\r\nhi",
 
47		"fetch 1 (bodystructure)",
 
48		`store 1 flags (\seen \answered)`,
 
49		`store 1 +flags ($junk)`,
 
50		`store 1 -flags ($junk)`,
 
57	for _, cmd := range seed {
 
62	log := mlog.New("imapserver", nil)
 
64	mox.ConfigStaticPath = filepath.FromSlash("../testdata/imapserverfuzz/mox.conf")
 
65	mox.MustLoadConfig(true, false)
 
66	dataDir := mox.ConfigDirPath(mox.Conf.Static.DataDir)
 
68	acc, err := store.OpenAccount(log, "mjl")
 
70		f.Fatalf("open account: %v", err)
 
76	err = acc.SetPassword(log, password0)
 
78		f.Fatalf("set password: %v", err)
 
80	defer store.Switchboard()()
 
82	comm := store.RegisterComm(acc)
 
83	defer comm.Unregister()
 
89		fl, err = os.OpenFile("fuzz.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
 
95	flog := func(err error, msg string) {
 
96		if fl != nil && err != nil {
 
97			fmt.Fprintf(fl, "%s: %v\n", msg, err)
 
101	f.Fuzz(func(t *testing.T, s string) {
 
102		run := func(cmds []string) {
 
103			limitersInit() // Reset rate limiters.
 
104			serverConn, clientConn := net.Pipe()
 
105			defer serverConn.Close()
 
110					// Protocol can become botched, when fuzzer sends literals.
 
115					if !ok || (!errors.Is(err, os.ErrDeadlineExceeded) && !errors.Is(err, io.EOF)) {
 
120				defer clientConn.Close()
 
122				err := clientConn.SetDeadline(time.Now().Add(time.Second))
 
123				flog(err, "set client deadline")
 
124				client, _ := imapclient.New(clientConn, true)
 
126				for _, cmd := range cmds {
 
127					client.Commandf("", "%s", cmd)
 
130				client.Commandf("", "%s", s)
 
134			err = serverConn.SetDeadline(time.Now().Add(time.Second))
 
135			flog(err, "set server deadline")
 
136			serve("test", cid, nil, serverConn, false, true)
 
140		// Each command brings the connection state one step further. We try the fuzzing
 
141		// input for each state.
 
143		run([]string{`login mjl@mox.example "` + password0 + `"`})
 
144		run([]string{`login mjl@mox.example "` + password0 + `"`, "select inbox"})
 
145		xappend := fmt.Sprintf("append inbox () {%d+}\r\n%s", len(exampleMsg), exampleMsg)
 
146		run([]string{`login mjl@mox.example "` + password0 + `"`, "select inbox", xappend})