Skip to content

Commit 9b647d9

Browse files
Merge pull request #301 from projectdiscovery/44_introduce_realtime_output
introduce realtime output
2 parents 73edfe1 + edfa8b7 commit 9b647d9

1 file changed

Lines changed: 41 additions & 39 deletions

File tree

internal/runner/enumerate.go

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func (r *Runner) EnumerateSingleQueryWithCtx(ctx context.Context, query string,
5151
now := time.Now()
5252
results := r.agent.EnumerateQueriesWithCtx(ctx, query, r.options.Proxy, r.options.RateLimit, r.options.Timeout, time.Duration(r.options.MaxEnumerationTime)*time.Minute, agent.WithCustomRateLimit(r.rateLimit))
5353

54+
outputWriter := NewOutputWriter(r.options.JSON)
5455
wg := &sync.WaitGroup{}
5556
wg.Add(1)
5657
// Create a unique map for filtering duplicate domains out
@@ -82,7 +83,9 @@ func (r *Runner) EnumerateSingleQueryWithCtx(ctx context.Context, query string,
8283

8384
// Log the verbose message about the found domain per source
8485
if _, ok := sourceMap[domain][result.Source]; !ok {
85-
gologger.Verbose().Label(result.Source).Msg(domain)
86+
if r.options.Verbose {
87+
gologger.Verbose().Label(result.Source).Msg(domain)
88+
}
8689
}
8790

8891
sourceMap[domain][result.Source] = struct{}{}
@@ -97,10 +100,27 @@ func (r *Runner) EnumerateSingleQueryWithCtx(ctx context.Context, query string,
97100

98101
uniqueMap[domain] = hostEntry
99102
// If the user asked to remove wildcard then send on the resolve
100-
// queue. Otherwise, if mode is not verbose print the results on
101-
// the screen as they are discovered.
103+
// queue. Otherwise, output results immediately as they are discovered.
102104
if r.options.RemoveWildcard {
103105
resolutionPool.Tasks <- hostEntry
106+
} else {
107+
for _, writer := range writers {
108+
var err error
109+
if r.options.CaptureSources {
110+
hostSourceMap := map[string]map[string]struct{}{domain: sourceMap[domain]}
111+
err = outputWriter.WriteSourceHost(query, hostSourceMap, writer)
112+
} else {
113+
hostMap := map[string]resolve.HostEntry{domain: hostEntry}
114+
err = outputWriter.WriteHost(query, hostMap, writer)
115+
}
116+
if err != nil {
117+
gologger.Error().Msgf("Could not write result for %s: %s\n", domain, err)
118+
}
119+
}
120+
// Call result callback if set
121+
if r.options.ResultCallback != nil {
122+
r.options.ResultCallback(&hostEntry)
123+
}
104124
}
105125
}
106126
}
@@ -113,7 +133,7 @@ func (r *Runner) EnumerateSingleQueryWithCtx(ctx context.Context, query string,
113133
}()
114134

115135
// If the user asked to remove wildcards, listen from the results
116-
// queue and write to the map. At the end, print the found results to the screen
136+
// queue and write results in real-time
117137
foundResults := make(map[string]resolve.Result)
118138
if r.options.RemoveWildcard {
119139
// Process the results coming from the resolutions pool
@@ -122,36 +142,30 @@ func (r *Runner) EnumerateSingleQueryWithCtx(ctx context.Context, query string,
122142
case resolve.Error:
123143
gologger.Warning().Msgf("Could not resolve host: %s\n", result.Error)
124144
case resolve.Subdomain:
125-
// Add the found domain to a map.
145+
// Add the found domain to a map and output immediately
126146
if _, ok := foundResults[result.Host]; !ok {
127147
foundResults[result.Host] = result
148+
for _, writer := range writers {
149+
var err error
150+
if r.options.HostIP {
151+
resultMap := map[string]resolve.Result{result.Host: result}
152+
err = outputWriter.WriteHostIP(query, resultMap, writer)
153+
} else {
154+
resultMap := map[string]resolve.Result{result.Host: result}
155+
err = outputWriter.WriteHostNoWildcard(query, resultMap, writer)
156+
}
157+
if err != nil {
158+
gologger.Error().Msgf("Could not write result for %s: %s\n", result.Host, err)
159+
}
160+
}
161+
if r.options.ResultCallback != nil {
162+
r.options.ResultCallback(&resolve.HostEntry{Query: query, Host: result.Host, Source: result.Source})
163+
}
128164
}
129165
}
130166
}
131167
}
132168
wg.Wait()
133-
outputWriter := NewOutputWriter(r.options.JSON)
134-
// Now output all results in output writers
135-
var err error
136-
for _, writer := range writers {
137-
if r.options.HostIP {
138-
err = outputWriter.WriteHostIP(query, foundResults, writer)
139-
} else {
140-
if r.options.RemoveWildcard {
141-
err = outputWriter.WriteHostNoWildcard(query, foundResults, writer)
142-
} else {
143-
if r.options.CaptureSources {
144-
err = outputWriter.WriteSourceHost(query, sourceMap, writer)
145-
} else {
146-
err = outputWriter.WriteHost(query, uniqueMap, writer)
147-
}
148-
}
149-
}
150-
if err != nil {
151-
gologger.Error().Msgf("Could not write results for %s: %s\n", query, err)
152-
return err
153-
}
154-
}
155169

156170
// Show found domain count in any case.
157171
duration := durafmt.Parse(time.Since(now)).LimitFirstN(maxNumCount).String()
@@ -161,18 +175,6 @@ func (r *Runner) EnumerateSingleQueryWithCtx(ctx context.Context, query string,
161175
} else {
162176
numberOfDomains = len(uniqueMap)
163177
}
164-
165-
if r.options.ResultCallback != nil {
166-
if r.options.RemoveWildcard {
167-
for host, result := range foundResults {
168-
r.options.ResultCallback(&resolve.HostEntry{Query: host, Host: result.Host, Source: result.Source})
169-
}
170-
} else {
171-
for _, v := range uniqueMap {
172-
r.options.ResultCallback(&v)
173-
}
174-
}
175-
}
176178
gologger.Info().Msgf("Found %d domains for %s in %s\n", numberOfDomains, query, duration)
177179

178180
if r.options.Statistics {

0 commit comments

Comments
 (0)