diff --git a/README.md b/README.md index 5b97b97..0c7cc6b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ As a countermeasure, use the `--restrict-to-peers` flags to only allow connectio ### Quickstart -- On your host 10.0.0.1: `./afl-transmit --fuzzer-directory /ram/output --peers 10.0.0.2,10.0.0.3` -- On your host 10.0.0.2: `./afl-transmit --fuzzer-directory /ram/output --peers 10.0.0.1,10.0.0.3` -- On your host 10.0.0.3: `./afl-transmit --fuzzer-directory /ram/output --peers 10.0.0.1,10.0.0.2` +- On your host 10.0.0.1: `./afl-transmit --fuzzer-directory /ram/output --main --peers 10.0.0.2,10.0.0.3` +- On your host 10.0.0.2: `./afl-transmit --fuzzer-directory /ram/output --peers 10.0.0.1` +- On your host 10.0.0.3: `./afl-transmit --fuzzer-directory /ram/output --peers 10.0.0.1` diff --git a/watchdog/watchdog.go b/watchdog/watchdog.go index c33db6f..6a49000 100644 --- a/watchdog/watchdog.go +++ b/watchdog/watchdog.go @@ -14,21 +14,21 @@ import ( var ( rescanSecs int + isMainNode bool ) // Register flags func RegisterWatchdogFlags() { flag.IntVar(&rescanSecs, "rescan-secs", 30, "Seconds to wait before rescanning local fuzzer directories") + flag.BoolVar(&isMainNode, "main", false, "Set this option if this afl-transmit instance is running on the node running the main afl-fuzz instance") } // Watch over the specified directory, send updates to peers and re-scan after the specified amount of seconds func WatchFuzzers(outputDirectory string) { // Loop forever for { - localFuzzers := detectLocalFuzzers(outputDirectory) - - // Loop over local fuzzers - for _, localFuzzDir := range localFuzzers { + // Loop over those fuzzer directories we want to share + for _, localFuzzDir := range getTargetFuzzers(outputDirectory) { // Pack important parts of the fuzzer directory into a byte array fuzzerName := filepath.Base(localFuzzDir) packedFuzzer, packerErr := logistic.PackFuzzer(fuzzerName, localFuzzDir) @@ -46,35 +46,79 @@ func WatchFuzzers(outputDirectory string) { } } -// Searches in the specified output directory for fuzzers which run locally. This is done by searching for a file which is not shared between fuzzers as it is not required for clusterized fuzzing: 'cmdline'. -func detectLocalFuzzers(outputDirectory string) []string { - var localFuzzers []string +// Searches in the specified output directory for fuzzers which we want to pack. +// Identifying the main fuzzer is done by searching for the file "is_main_node" +// Identifying local secondary fuzzers is done by searching for a file which is not shared between nodes as it is not required for clusterized fuzzing: 'cmdline'. +// Please note that this is not failsafe, e.g. if you already synced your fuzzers over a different tool or by hand before. +// +// - If we are running in main mode (--main), we want to share the main fuzzers' queue with the secondary nodes +// - If we are not running in main mode, we want to share all of our fuzzers' queues with the main node +// +// (see AFLplusplus/src/afl-fuzz.run.c:542) +func getTargetFuzzers(outputDirectory string) []string { + if isMainNode { + // find main fuzzer directory - its the only one required by the secondaries - // List files (read: fuzzers) in output directory - filesInDir, readErr := ioutil.ReadDir(outputDirectory) - if readErr != nil { - log.Printf("Failed to list directory content of %s: %s", outputDirectory, readErr) - return nil - } - - // Walk over each and search for 'cmdline' file - for _, f := range filesInDir { - // Get stat for maybe-existent file - cmdlinePath := fmt.Sprintf("%s%c%s%ccmdline", outputDirectory, os.PathSeparator, f.Name(), os.PathSeparator) - _, statErr := os.Stat(cmdlinePath) - if os.IsNotExist(statErr) { - // File does not exist. That's fine. Next. - continue - } else if statErr != nil { - // An error occurred. File is maybe in a Schrödinger state. - log.Printf("Unable to stat file %s: %s", cmdlinePath, statErr) - continue + // List files (read: fuzzers) in output directory + filesInDir, readErr := ioutil.ReadDir(outputDirectory) + if readErr != nil { + log.Printf("Failed to list directory content of %s: %s", outputDirectory, readErr) + return nil } - // File exists, let's watch it - fullPath := fmt.Sprintf("%s%c%s", outputDirectory, os.PathSeparator, f.Name()) - localFuzzers = append(localFuzzers, fullPath) - } + for _, f := range filesInDir { + // Get stat for maybe-existent file + mainnodePath := fmt.Sprintf("%s%c%s%cis_main_node", outputDirectory, os.PathSeparator, f.Name(), os.PathSeparator) + _, statErr := os.Stat(mainnodePath) + if os.IsNotExist(statErr) { + // File does not exist. Not the ~~chosen one~~ main fuzzer. Next. + continue + } else if statErr != nil { + // An error occurred. File is maybe in a Schrödinger state. + log.Printf("Unable to stat file %s: %s", mainnodePath, statErr) + continue + } - return localFuzzers + // is_main_node file exists, so we found the correct fuzzer directory - return it + fullPath := fmt.Sprintf("%s%c%s", outputDirectory, os.PathSeparator, f.Name()) + return []string{ + fullPath, + } + } + + // Failed to find the main node - probably we are in --main mode by accident + log.Printf("Unable to find main node in %s - sure afl-transmit should run in --main mode?", outputDirectory) + return nil + } else { + // get all fuzzer directories which are locally available + var localFuzzers []string + + // List files (read: fuzzers) in output directory + filesInDir, readErr := ioutil.ReadDir(outputDirectory) + if readErr != nil { + log.Printf("Failed to list directory content of %s: %s", outputDirectory, readErr) + return nil + } + + // Walk over each fuzzer and search for 'cmdline' file + for _, f := range filesInDir { + // Get stat for maybe-existent file + cmdlinePath := fmt.Sprintf("%s%c%s%ccmdline", outputDirectory, os.PathSeparator, f.Name(), os.PathSeparator) + _, statErr := os.Stat(cmdlinePath) + if os.IsNotExist(statErr) { + // File does not exist. That's fine. Next. + continue + } else if statErr != nil { + // An error occurred. File is maybe in a Schrödinger state. + log.Printf("Unable to stat file %s: %s", cmdlinePath, statErr) + continue + } + + // File exists, let's watch it + fullPath := fmt.Sprintf("%s%c%s", outputDirectory, os.PathSeparator, f.Name()) + localFuzzers = append(localFuzzers, fullPath) + } + + return localFuzzers + } }