From e4e4f5bfcec36259f751b5cc2b9744438bd0c0a8 Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Wed, 23 Feb 2022 17:41:23 +0100 Subject: [PATCH 01/10] Use RAM-friendly algorithm and write output in chunks --- go.mod | 2 +- main.go | 245 +++++++++++++++++++++++++++++++++++++++++++++++++ mksub.go | 200 ---------------------------------------- round/round.go | 34 +++++++ 4 files changed, 280 insertions(+), 201 deletions(-) create mode 100644 main.go delete mode 100644 mksub.go create mode 100644 round/round.go diff --git a/go.mod b/go.mod index c0ecf8b..19474bd 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module main +module mksub go 1.17 diff --git a/main.go b/main.go new file mode 100644 index 0000000..99134a3 --- /dev/null +++ b/main.go @@ -0,0 +1,245 @@ +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + roundChan "mksub/round" + "os" + "os/signal" + "regexp" + "strconv" + "strings" + "sync" + "syscall" +) + +const ( + bufferSizeMB = 100 + maxWorkingThreads = 100000 +) + +var ( + inputDomains []string + wordSet map[string]bool + words []string +) + +var ( + domain string + domainFile string + wordlist string + regex string + nf int + level int + workers int + outputFile string + + workerThreadMax = make(chan struct{}, maxWorkingThreads) + done = make(chan struct{}) + wg sync.WaitGroup + wgWrite sync.WaitGroup + robin roundChan.RoundRobin +) + +func readDomainFile() { + inputFile, err := os.Open(domainFile) + if err != nil { + panic("Could not open file to read domains!") + } + defer inputFile.Close() + + scanner := bufio.NewScanner(inputFile) + for scanner.Scan() { + inputDomains = append(inputDomains, strings.TrimSpace(scanner.Text())) + } +} + +func prepareDomains() { + if domain == "" && domainFile == "" { + fmt.Println("No domain input provided") + os.Exit(1) + } + + inputDomains = make([]string, 0) + if domain != "" { + inputDomains = append(inputDomains, domain) + } else { + if domainFile != "" { + readDomainFile() + } + } +} + +func readWordlistFile() { + var reg *regexp.Regexp + var err error + if regex != "" { + reg, err = regexp.Compile(regex) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } + + wordlistFile, err := os.Open(wordlist) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + defer wordlistFile.Close() + + wordSet = make(map[string]bool) + scanner := bufio.NewScanner(wordlistFile) + for scanner.Scan() { + word := strings.ToLower(scanner.Text()) + word = strings.Trim(word, ".") + if reg != nil { + if !reg.Match([]byte(word)) { + continue + } + } + + if word != "" { + wordSet[word] = true + } + } + + for w := range wordSet { + words = append(words, w) + } +} + +func closeWriters(number int) { + for i := 0; i < number; i++ { + done <- struct{}{} + } +} + +func spawnWriters(number int) { + for i := 0; i < number; i++ { + var bf bytes.Buffer + ch := make(chan string, 100000) + + fileName := outputFile + if number > 1 { + fileName += "-" + strconv.Itoa(i) + } + file, _ := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) + + wgWrite.Add(1) + go write(file, &bf, &ch) + + if robin == nil { + robin = roundChan.New(&ch) + continue + } + robin.Add(&ch) + } +} + +func write(file *os.File, buffer *bytes.Buffer, ch *chan string) { +mainLoop: + for { + select { + case <-done: + for { + if !writeOut(file, buffer, ch) { + break + } + } + if buffer.Len() > 0 { + if file != nil { + _, _ = file.WriteString(buffer.String()) + buffer.Reset() + } + } + break mainLoop + default: + writeOut(file, buffer, ch) + } + } + wgWrite.Done() +} +func writeOut(file *os.File, buffer *bytes.Buffer, outputChannel *chan string) bool { + select { + case s := <-*outputChannel: + buffer.WriteString(s) + if buffer.Len() >= bufferSizeMB*1024*1024 { + _, _ = file.WriteString(buffer.String()) + buffer.Reset() + } + return true + default: + return false + } +} + +func combo(_comb string, level int, wg *sync.WaitGroup, wt *chan struct{}) { + defer wg.Done() + workerThreadMax <- struct{}{} + + if strings.Count(_comb, ".") > 1 { + *robin.Next() <- _comb + "\n" + } + + var nextLevelWaitGroup sync.WaitGroup + if level > 1 { + nextLevelWt := make(chan struct{}, workers) + for _, c := range words { + nextLevelWaitGroup.Add(1) + nextLevelWt <- struct{}{} + go combo(c+"."+_comb, level-1, &nextLevelWaitGroup, &nextLevelWt) + } + } else { + for _, c := range words { + *robin.Next() <- c + "." + _comb + "\n" + } + } + + nextLevelWaitGroup.Wait() + <-workerThreadMax + <-*wt +} + +func main() { + flag.StringVar(&domain, "d", "", "Input domain") + flag.StringVar(&domainFile, "df", "", "Input domain file, one domain per line") + flag.StringVar(&wordlist, "w", "", "Wordlist file") + flag.StringVar(®ex, "r", "", "Regex to filter words from wordlist file") + flag.IntVar(&level, "l", 1, "Subdomain level to generate") + flag.StringVar(&outputFile, "o", "mksub-out", "Output file (optional)") + flag.IntVar(&workers, "t", 100, "Number of threads for every subdomain level") + flag.IntVar(&nf, "nf", 1, "Number of files to split the output into (faster with multiple files)") + flag.Parse() + + go func() { + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM, syscall.SIGKILL) + <-signalChannel + + fmt.Println("Program interrupted, exiting...") + os.Exit(0) + }() + + if level <= 0 || workers <= 0 { + fmt.Println("Subdomain level and number of threads must be positive integers!") + os.Exit(0) + } + + prepareDomains() + readWordlistFile() + spawnWriters(nf) + + for _, d := range inputDomains { + wg.Add(1) + wt := make(chan struct{}, 1) + wt <- struct{}{} + go combo(d, level, &wg, &wt) + } + + wg.Wait() + closeWriters(nf) + wgWrite.Wait() +} diff --git a/mksub.go b/mksub.go deleted file mode 100644 index 5465b4b..0000000 --- a/mksub.go +++ /dev/null @@ -1,200 +0,0 @@ -package main - -import ( - "bufio" - "flag" - "fmt" - "os" - "os/signal" - "regexp" - "strings" - "sync" - "syscall" -) - -var ( - //flags - domain *string - domainFile *string - wordlist *string - regex *string - level *int - output *string - threads *int - - inputDomains []string - wordlistCombinations []string - wordSet map[string]bool - outputChannel chan string - maxConcurrencyLevel = 1000000 - threadSemaphore chan bool -) - -func fileReadDomain(fileName string) { - inputFile, err := os.Open(fileName) - if err != nil { - panic("Could not open file to read domains!") - } - defer inputFile.Close() - - scanner := bufio.NewScanner(inputFile) - for scanner.Scan() { - inputDomains = append(inputDomains, strings.TrimSpace(scanner.Text())) - } -} - -func prepareDomains() { - if *domain == "" && *domainFile == "" { - fmt.Println("No domain input provided") - os.Exit(1) - } - - inputDomains = make([]string, 0) - if *domain != "" { - inputDomains = append(inputDomains, *domain) - } else { - if *domainFile != "" { - fileReadDomain(*domainFile) - } - } - -} - -func processDomain(domain string, wg *sync.WaitGroup) { - defer wg.Done() - defer func() { - <-threadSemaphore - }() - - for _, word := range wordlistCombinations { - outputChannel <- word + "." + domain - } - -} - -func writeOutput(wg *sync.WaitGroup) { - defer wg.Done() - - var outputFile *os.File - var err error - if *output != "" { - outputFile, err = os.Create(*output) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - defer outputFile.Close() - } - - for data := range outputChannel { - fmt.Println(data) - if outputFile != nil { - _, _ = outputFile.WriteString(data + "\n") - } - } -} - -func generateWordlistCombinations() { - var reg *regexp.Regexp - var err error - if *regex != "" { - reg, err = regexp.Compile(*regex) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - } - - wordlistFile, err := os.Open(*wordlist) - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - defer wordlistFile.Close() - - wordSet = make(map[string]bool) - scanner := bufio.NewScanner(wordlistFile) - for scanner.Scan() { - word := strings.ToLower(scanner.Text()) - word = strings.Trim(word, ".") - if reg != nil { - if !reg.Match([]byte(word)) { - continue - } - } - - if word != "" { - wordSet[word] = true - } - } - - wordlistCombinations = make([]string, 0) - for word := range wordSet { - wordlistCombinations = append(wordlistCombinations, word) - } - - for i := 0; i < *level-1; i++ { - for j := 0; j < len(wordlistCombinations)-j*len(wordSet); j++ { - sd := wordlistCombinations[j] - for word := range wordSet { - wordlistCombinations = append(wordlistCombinations, word+"."+sd) - } - } - } -} - -func main() { - domain = flag.String("d", "", "Input domain") - domainFile = flag.String("df", "", "Input domain file, one domain per line") - wordlist = flag.String("w", "", "Wordlist file") - regex = flag.String("r", "", "Regex to filter words from wordlist file") - level = flag.Int("l", 1, "Subdomain level to generate") - output = flag.String("o", "", "Output file (optional)") - threads = flag.Int("t", 200, "Maximum number of threads to be used") - flag.Parse() - - go func() { - signalChannel := make(chan os.Signal, 1) - signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM, syscall.SIGKILL) - <-signalChannel - - fmt.Println("Program interrupted, exiting...") - os.Exit(0) - }() - - if *level <= 0 || *threads <= 0 { - fmt.Println("Subdomain level and number of threads must be positive integers!") - os.Exit(1) - } - - if *threads > maxConcurrencyLevel { - fmt.Println("Number of threads greater than the maximum number allowed (1000000)!") - os.Exit(1) - } - - prepareDomains() - generateWordlistCombinations() - - outputChannel = make(chan string, *threads*maxConcurrencyLevel) - - var outWg sync.WaitGroup - var inWg sync.WaitGroup - - outWg.Add(1) - go writeOutput(&outWg) - - if *threads > len(inputDomains) { - *threads = len(inputDomains) - } - threadSemaphore = make(chan bool, *threads) - - for _, dom := range inputDomains { - inWg.Add(1) - threadSemaphore <- true - go processDomain(dom, &inWg) - } - - inWg.Wait() - close(outputChannel) - outWg.Wait() -} diff --git a/round/round.go b/round/round.go new file mode 100644 index 0000000..b416927 --- /dev/null +++ b/round/round.go @@ -0,0 +1,34 @@ +package roundChan + +import ( + "sync/atomic" +) + +// RoundRobin is an interface for representing round-robin balancing. +type RoundRobin interface { + Next() *chan string + Add(*chan string) +} + +type roundRobin struct { + chs []*chan string + next uint32 +} + +// New returns RoundRobin implementation(*roundRobin). +func New(chs ...*chan string) RoundRobin { + return &roundRobin{ + chs: chs, + } +} + +// Next returns next channel +func (r *roundRobin) Next() *chan string { + n := atomic.AddUint32(&r.next, 1) + return r.chs[(int(n)-1)%len(r.chs)] +} + +// Add adds a channel +func (r *roundRobin) Add(ch *chan string) { + r.chs = append(r.chs, ch) +} From 7fc091fa07141161afaca23633ba891a2002891e Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Wed, 23 Feb 2022 18:23:39 +0100 Subject: [PATCH 02/10] Store output(s) inside a folder --- main.go | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/main.go b/main.go index 99134a3..3281d9a 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( roundChan "mksub/round" "os" "os/signal" + "path" "regexp" "strconv" "strings" @@ -27,14 +28,14 @@ var ( ) var ( - domain string - domainFile string - wordlist string - regex string - nf int - level int - workers int - outputFile string + domain string + domainFile string + wordlist string + regex string + nf int + level int + workers int + outputFolder string workerThreadMax = make(chan struct{}, maxWorkingThreads) done = make(chan struct{}) @@ -122,11 +123,15 @@ func spawnWriters(number int) { var bf bytes.Buffer ch := make(chan string, 100000) - fileName := outputFile + fileName := outputFolder if number > 1 { fileName += "-" + strconv.Itoa(i) } - file, _ := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) + file, err := os.Create(path.Join(outputFolder, fileName)) + if err != nil { + fmt.Println(err) + fmt.Println("Couldn't open file to write output!") + } wgWrite.Add(1) go write(file, &bf, &ch) @@ -209,7 +214,7 @@ func main() { flag.StringVar(&wordlist, "w", "", "Wordlist file") flag.StringVar(®ex, "r", "", "Regex to filter words from wordlist file") flag.IntVar(&level, "l", 1, "Subdomain level to generate") - flag.StringVar(&outputFile, "o", "mksub-out", "Output file (optional)") + flag.StringVar(&outputFolder, "o", "mksub-out", "Output folder (file(s) will use the same name)") flag.IntVar(&workers, "t", 100, "Number of threads for every subdomain level") flag.IntVar(&nf, "nf", 1, "Number of files to split the output into (faster with multiple files)") flag.Parse() @@ -228,6 +233,18 @@ func main() { os.Exit(0) } + dirInfo, err := os.Stat(outputFolder) + dirExists := !os.IsNotExist(err) && dirInfo.IsDir() + + if !dirExists { + err = os.Mkdir(outputFolder, 0755) + if err != nil { + fmt.Println(err) + fmt.Println("Couldn't create a directory to store outputs!") + os.Exit(0) + } + } + prepareDomains() readWordlistFile() spawnWriters(nf) From c96c45703fe7129224c318e47c5202834b7d1807 Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Wed, 23 Feb 2022 18:24:49 +0100 Subject: [PATCH 03/10] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1530db5..6609bbd 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,14 @@ Usage of mksub: Input domain file, one domain per line -l int Subdomain level to generate (default 1) + -nf int + Number of files to split the output into (faster with multiple files) (default 1) -o string - Output file (optional) + Output folder (file(s) will use the same name) (default "mksub-out") -r string Regex to filter words from wordlist file -t int - Maximum number of threads to be used (default 200) + Number of threads for every subdomain level (default 100) -w string Wordlist file ``` From 21a9a45c2948774b41de48460c7510ce65554bfd Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Wed, 23 Feb 2022 18:32:17 +0100 Subject: [PATCH 04/10] Add silent flag --- main.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main.go b/main.go index 3281d9a..d7e4aad 100644 --- a/main.go +++ b/main.go @@ -36,6 +36,7 @@ var ( level int workers int outputFolder string + silent bool workerThreadMax = make(chan struct{}, maxWorkingThreads) done = make(chan struct{}) @@ -186,6 +187,9 @@ func combo(_comb string, level int, wg *sync.WaitGroup, wt *chan struct{}) { workerThreadMax <- struct{}{} if strings.Count(_comb, ".") > 1 { + if !silent { + fmt.Print(_comb + "\n") + } *robin.Next() <- _comb + "\n" } @@ -199,6 +203,9 @@ func combo(_comb string, level int, wg *sync.WaitGroup, wt *chan struct{}) { } } else { for _, c := range words { + if !silent { + fmt.Print(c + "." + _comb + "\n") + } *robin.Next() <- c + "." + _comb + "\n" } } @@ -217,6 +224,7 @@ func main() { flag.StringVar(&outputFolder, "o", "mksub-out", "Output folder (file(s) will use the same name)") flag.IntVar(&workers, "t", 100, "Number of threads for every subdomain level") flag.IntVar(&nf, "nf", 1, "Number of files to split the output into (faster with multiple files)") + flag.BoolVar(&silent, "silent", true, "Skip writing generated subdomains to stdout (faster)") flag.Parse() go func() { From a8ade35c0d8f68069c39750d8152b6f82c4083fb Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Wed, 23 Feb 2022 18:33:18 +0100 Subject: [PATCH 05/10] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6609bbd..2b0782c 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ Usage of mksub: Output folder (file(s) will use the same name) (default "mksub-out") -r string Regex to filter words from wordlist file + -silent + Skip writing generated subdomains to stdout (faster) (default true) -t int Number of threads for every subdomain level (default 100) -w string From b56b855b9523a88199ed2c2dd1bcd2436f3a3548 Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Fri, 25 Feb 2022 11:40:24 +0100 Subject: [PATCH 06/10] Create nested folders if -o contains slashes; Add output file flag --- main.go | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index d7e4aad..2e4dd7a 100644 --- a/main.go +++ b/main.go @@ -36,6 +36,7 @@ var ( level int workers int outputFolder string + outputFile string silent bool workerThreadMax = make(chan struct{}, maxWorkingThreads) @@ -124,9 +125,15 @@ func spawnWriters(number int) { var bf bytes.Buffer ch := make(chan string, 100000) - fileName := outputFolder + fileName := outputFile + fileSplit := strings.Split(fileName, ".") + if len(fileSplit) == 1 { + fileName += ".txt" + } if number > 1 { - fileName += "-" + strconv.Itoa(i) + fileSplit = strings.Split(fileName, ".") + extension := "." + fileSplit[len(fileSplit)-1] + fileName = strings.TrimSuffix(fileName, extension) + "-" + strconv.Itoa(i) + extension } file, err := os.Create(path.Join(outputFolder, fileName)) if err != nil { @@ -221,7 +228,8 @@ func main() { flag.StringVar(&wordlist, "w", "", "Wordlist file") flag.StringVar(®ex, "r", "", "Regex to filter words from wordlist file") flag.IntVar(&level, "l", 1, "Subdomain level to generate") - flag.StringVar(&outputFolder, "o", "mksub-out", "Output folder (file(s) will use the same name)") + flag.StringVar(&outputFolder, "o", "", "Output folder (stdout will be used when omitted)") + flag.StringVar(&outputFile, "file", "output.txt", "Output file(s) name") flag.IntVar(&workers, "t", 100, "Number of threads for every subdomain level") flag.IntVar(&nf, "nf", 1, "Number of files to split the output into (faster with multiple files)") flag.BoolVar(&silent, "silent", true, "Skip writing generated subdomains to stdout (faster)") @@ -241,15 +249,24 @@ func main() { os.Exit(0) } - dirInfo, err := os.Stat(outputFolder) - dirExists := !os.IsNotExist(err) && dirInfo.IsDir() - - if !dirExists { - err = os.Mkdir(outputFolder, 0755) - if err != nil { - fmt.Println(err) - fmt.Println("Couldn't create a directory to store outputs!") - os.Exit(0) + if outputFolder == "" { + silent = false + } else { + dirPath := strings.Split(outputFolder, "/") + toMerge := "" + for _, dir := range dirPath { + toMerge = path.Join(toMerge, dir) + dirInfo, err := os.Stat(toMerge) + dirExists := !os.IsNotExist(err) && dirInfo.IsDir() + + if !dirExists { + err = os.Mkdir(toMerge, 0755) + if err != nil { + fmt.Println(err) + fmt.Println("Couldn't create a directory to store outputs!") + os.Exit(0) + } + } } } From 5ae2d67beee696ba2cd30fb59f7a37080144f391 Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Fri, 25 Feb 2022 12:18:52 +0100 Subject: [PATCH 07/10] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b0782c..52bc941 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,14 @@ Usage of mksub: Input domain -df string Input domain file, one domain per line + -file string + Output file(s) name (default "output.txt") -l int Subdomain level to generate (default 1) -nf int Number of files to split the output into (faster with multiple files) (default 1) -o string - Output folder (file(s) will use the same name) (default "mksub-out") + Output folder (stdout will be used when omitted) -r string Regex to filter words from wordlist file -silent From 09ef9b7ccef3aeb6311e24f0c413c90ee55a014b Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Fri, 25 Feb 2022 15:47:47 +0100 Subject: [PATCH 08/10] Trim slashes from output folder name --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 2e4dd7a..9657f33 100644 --- a/main.go +++ b/main.go @@ -252,7 +252,7 @@ func main() { if outputFolder == "" { silent = false } else { - dirPath := strings.Split(outputFolder, "/") + dirPath := strings.Split(strings.Trim(outputFolder, "/"), "/") toMerge := "" for _, dir := range dirPath { toMerge = path.Join(toMerge, dir) From 4774360d9be5b80a16a3970b0eb0dcfbd1ad3829 Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Fri, 25 Feb 2022 16:47:04 +0100 Subject: [PATCH 09/10] Remove output folder and file split --- main.go | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/main.go b/main.go index 9657f33..3ee1e48 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( roundChan "mksub/round" "os" "os/signal" - "path" "regexp" "strconv" "strings" @@ -19,6 +18,7 @@ import ( const ( bufferSizeMB = 100 maxWorkingThreads = 100000 + numberOfFiles = 1 ) var ( @@ -28,16 +28,14 @@ var ( ) var ( - domain string - domainFile string - wordlist string - regex string - nf int - level int - workers int - outputFolder string - outputFile string - silent bool + domain string + domainFile string + wordlist string + regex string + level int + workers int + outputFile string + silent bool workerThreadMax = make(chan struct{}, maxWorkingThreads) done = make(chan struct{}) @@ -135,7 +133,7 @@ func spawnWriters(number int) { extension := "." + fileSplit[len(fileSplit)-1] fileName = strings.TrimSuffix(fileName, extension) + "-" + strconv.Itoa(i) + extension } - file, err := os.Create(path.Join(outputFolder, fileName)) + file, err := os.Create(fileName) if err != nil { fmt.Println(err) fmt.Println("Couldn't open file to write output!") @@ -228,10 +226,8 @@ func main() { flag.StringVar(&wordlist, "w", "", "Wordlist file") flag.StringVar(®ex, "r", "", "Regex to filter words from wordlist file") flag.IntVar(&level, "l", 1, "Subdomain level to generate") - flag.StringVar(&outputFolder, "o", "", "Output folder (stdout will be used when omitted)") - flag.StringVar(&outputFile, "file", "output.txt", "Output file(s) name") + flag.StringVar(&outputFile, "o", "", "Output file (stdout will be used when omitted)") flag.IntVar(&workers, "t", 100, "Number of threads for every subdomain level") - flag.IntVar(&nf, "nf", 1, "Number of files to split the output into (faster with multiple files)") flag.BoolVar(&silent, "silent", true, "Skip writing generated subdomains to stdout (faster)") flag.Parse() @@ -249,30 +245,13 @@ func main() { os.Exit(0) } - if outputFolder == "" { + if outputFile == "" { silent = false - } else { - dirPath := strings.Split(strings.Trim(outputFolder, "/"), "/") - toMerge := "" - for _, dir := range dirPath { - toMerge = path.Join(toMerge, dir) - dirInfo, err := os.Stat(toMerge) - dirExists := !os.IsNotExist(err) && dirInfo.IsDir() - - if !dirExists { - err = os.Mkdir(toMerge, 0755) - if err != nil { - fmt.Println(err) - fmt.Println("Couldn't create a directory to store outputs!") - os.Exit(0) - } - } - } } prepareDomains() readWordlistFile() - spawnWriters(nf) + spawnWriters(numberOfFiles) for _, d := range inputDomains { wg.Add(1) @@ -282,6 +261,6 @@ func main() { } wg.Wait() - closeWriters(nf) + closeWriters(numberOfFiles) wgWrite.Wait() } From c8122e24b839b1d22a6869f90080723229e97587 Mon Sep 17 00:00:00 2001 From: PolovinaD Date: Fri, 25 Feb 2022 16:47:20 +0100 Subject: [PATCH 10/10] Update README.md --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 52bc941..b356ea5 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,10 @@ Usage of mksub: Input domain -df string Input domain file, one domain per line - -file string - Output file(s) name (default "output.txt") -l int Subdomain level to generate (default 1) - -nf int - Number of files to split the output into (faster with multiple files) (default 1) -o string - Output folder (stdout will be used when omitted) + Output file (stdout will be used when omitted) -r string Regex to filter words from wordlist file -silent