Skip to content

Commit 86ec9a0

Browse files
committed
Improve IP lookup pools and cancel handling
1 parent 5d46990 commit 86ec9a0

5 files changed

Lines changed: 838 additions & 8 deletions

File tree

internal/cli/cli.go

Lines changed: 234 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cli
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"strings"
78
"time"
@@ -10,26 +11,39 @@ import (
1011
)
1112

1213
type App struct {
13-
inputTimeout time.Duration
14+
inputTimeout time.Duration
15+
lookupTimeout time.Duration
1416
}
1517

1618
func NewApp() *App {
17-
return &App{inputTimeout: 3 * time.Second}
19+
return &App{
20+
inputTimeout: 3 * time.Second,
21+
lookupTimeout: 45 * time.Second,
22+
}
1823
}
1924

2025
func (a *App) Run() error {
2126
for {
2227
config, err := a.collectConfig()
2328
if err != nil {
29+
if errors.Is(err, errAborted) {
30+
return nil
31+
}
2432
return err
2533
}
2634

2735
if err := a.execute(config); err != nil {
36+
if errors.Is(err, errAborted) {
37+
return nil
38+
}
2839
return err
2940
}
3041

3142
again, err := a.askAgain()
3243
if err != nil {
44+
if errors.Is(err, errAborted) {
45+
return nil
46+
}
3347
return err
3448
}
3549
if !again {
@@ -39,28 +53,117 @@ func (a *App) Run() error {
3953
}
4054

4155
type Config struct {
56+
Mode Mode
57+
Direct DirectConfig
58+
Lookup LookupConfig
59+
}
60+
61+
func (a *App) collectConfig() (Config, error) {
62+
mode, err := a.askMode()
63+
if err != nil {
64+
return Config{}, err
65+
}
66+
67+
if mode == ModeLookup {
68+
lookup, err := a.collectLookupConfig()
69+
if err != nil {
70+
return Config{}, err
71+
}
72+
return Config{Mode: mode, Lookup: lookup}, nil
73+
}
74+
75+
direct, err := a.collectDirectConfig()
76+
if err != nil {
77+
return Config{}, err
78+
}
79+
80+
return Config{Mode: mode, Direct: direct}, nil
81+
}
82+
83+
type Mode string
84+
85+
const (
86+
ModeDirect Mode = "direct"
87+
ModeLookup Mode = "lookup"
88+
)
89+
90+
type DirectConfig struct {
4291
Host string
4392
Port int
4493
Edition ping.Edition
4594
}
4695

47-
func (a *App) collectConfig() (Config, error) {
96+
type LookupConfig struct {
97+
Edition ping.Edition
98+
BaseHost string
99+
Port int
100+
Subdomains []string
101+
Endings []string
102+
}
103+
104+
func (a *App) collectDirectConfig() (DirectConfig, error) {
48105
edition, err := a.askEdition()
49106
if err != nil {
50-
return Config{}, err
107+
return DirectConfig{}, err
51108
}
52109

53110
host, err := a.askHost()
54111
if err != nil {
55-
return Config{}, err
112+
return DirectConfig{}, err
56113
}
57114

58115
port, err := a.askPort(edition)
59116
if err != nil {
60-
return Config{}, err
117+
return DirectConfig{}, err
61118
}
62119

63-
return Config{Host: host, Port: port, Edition: edition}, nil
120+
return DirectConfig{Host: host, Port: port, Edition: edition}, nil
121+
}
122+
123+
func (a *App) collectLookupConfig() (LookupConfig, error) {
124+
edition, err := a.askEdition()
125+
if err != nil {
126+
return LookupConfig{}, err
127+
}
128+
129+
subdomains, err := a.askSubdomainChoice()
130+
if err != nil {
131+
return LookupConfig{}, err
132+
}
133+
134+
baseHost, err := a.askBaseHost()
135+
if err != nil {
136+
return LookupConfig{}, err
137+
}
138+
139+
endings, err := a.askDomainEndings()
140+
if err != nil {
141+
return LookupConfig{}, err
142+
}
143+
144+
port, err := a.askPort(edition)
145+
if err != nil {
146+
return LookupConfig{}, err
147+
}
148+
149+
return LookupConfig{
150+
Edition: edition,
151+
BaseHost: baseHost,
152+
Port: port,
153+
Subdomains: subdomains,
154+
Endings: endings,
155+
}, nil
156+
}
157+
158+
func (a *App) askMode() (Mode, error) {
159+
index, err := selectOption("Startmodus", []string{"UWP/TCP Abfrage", "IP Lookup"})
160+
if err != nil {
161+
return "", err
162+
}
163+
if index == 1 {
164+
return ModeLookup, nil
165+
}
166+
return ModeDirect, nil
64167
}
65168

66169
func (a *App) askEdition() (ping.Edition, error) {
@@ -89,6 +192,69 @@ func (a *App) askHost() (string, error) {
89192
}
90193
}
91194

195+
func (a *App) askBaseHost() (string, error) {
196+
var errMsg string
197+
for {
198+
value, err := promptInput("IP/Domain ohne Endung", "z.B. example", errMsg)
199+
if err != nil {
200+
return "", err
201+
}
202+
value = strings.TrimSpace(value)
203+
if value == "" {
204+
errMsg = "Wert darf nicht leer sein"
205+
continue
206+
}
207+
return value, nil
208+
}
209+
}
210+
211+
func (a *App) askSubdomainChoice() ([]string, error) {
212+
index, err := selectOption("Subdomain", []string{"Eigene Subdomain", "Subdomain-Pool"})
213+
if err != nil {
214+
return nil, err
215+
}
216+
if index == 1 {
217+
return subdomainPool, nil
218+
}
219+
220+
var errMsg string
221+
for {
222+
value, err := promptInput("Subdomain (optional)", "z.B. play (leer lassen für keine)", errMsg)
223+
if err != nil {
224+
return nil, err
225+
}
226+
value = strings.TrimSpace(value)
227+
return []string{value}, nil
228+
}
229+
}
230+
231+
func (a *App) askDomainEndings() ([]string, error) {
232+
index, err := selectOption("Domain-Endung", []string{"Eigene Endung", "Endungs-Pool"})
233+
if err != nil {
234+
return nil, err
235+
}
236+
if index == 1 {
237+
endings, err := loadDomainEndings()
238+
if err != nil {
239+
return endings, nil
240+
}
241+
return endings, nil
242+
}
243+
var errMsg string
244+
for {
245+
value, err := promptInput("Domain-Endung", "z.B. com oder de", errMsg)
246+
if err != nil {
247+
return nil, err
248+
}
249+
value = normalizeEnding(value)
250+
if value == "" {
251+
errMsg = "Endung darf nicht leer sein"
252+
continue
253+
}
254+
return []string{value}, nil
255+
}
256+
}
257+
92258
func (a *App) askPort(edition ping.Edition) (int, error) {
93259
defaultPort := ping.DefaultPort(edition)
94260
var errMsg string
@@ -114,6 +280,15 @@ func (a *App) askPort(edition ping.Edition) (int, error) {
114280
}
115281

116282
func (a *App) execute(config Config) error {
283+
switch config.Mode {
284+
case ModeLookup:
285+
return a.executeLookup(config.Lookup)
286+
default:
287+
return a.executeDirect(config.Direct)
288+
}
289+
}
290+
291+
func (a *App) executeDirect(config DirectConfig) error {
117292
ctx, cancel := context.WithTimeout(context.Background(), a.inputTimeout)
118293
defer cancel()
119294

@@ -132,10 +307,62 @@ func (a *App) execute(config Config) error {
132307
return nil
133308
}
134309

310+
func (a *App) executeLookup(config LookupConfig) error {
311+
ctx, cancel := context.WithTimeout(context.Background(), a.lookupTimeout)
312+
defer cancel()
313+
314+
resultText, err := withSpinner("IP Lookup", "Domains werden überprüft", 120*time.Millisecond, func() (string, error) {
315+
result, lookupErr := ping.LookupDomains(ctx, ping.LookupConfig{
316+
Edition: config.Edition,
317+
Port: config.Port,
318+
BaseHost: config.BaseHost,
319+
Subdomains: config.Subdomains,
320+
DomainEndings: config.Endings,
321+
Concurrency: 24,
322+
PerHostTimeout: 2 * time.Second,
323+
})
324+
if lookupErr != nil && !errors.Is(lookupErr, context.DeadlineExceeded) {
325+
return "", lookupErr
326+
}
327+
return formatLookupResult(result, errors.Is(lookupErr, context.DeadlineExceeded)), nil
328+
})
329+
if err != nil {
330+
return err
331+
}
332+
333+
renderTextPage("Ergebnis", resultText)
334+
return nil
335+
}
336+
135337
func (a *App) askAgain() (bool, error) {
136338
index, err := selectOption("Nächster Schritt", []string{"Neue Abfrage", "Beenden"})
137339
if err != nil {
138340
return false, err
139341
}
140342
return index == 0, nil
141343
}
344+
345+
func formatLookupResult(result ping.LookupResult, timedOut bool) string {
346+
var builder strings.Builder
347+
builder.WriteString(fmt.Sprintf("Kombinationen geprüft: %d/%d\n", result.Completed, result.Attempts))
348+
builder.WriteString(fmt.Sprintf("Treffer: %d\n", len(result.Matches)))
349+
if timedOut {
350+
builder.WriteString("Hinweis: Zeitlimit erreicht, Ergebnisse können unvollständig sein.\n")
351+
}
352+
builder.WriteString("\n")
353+
354+
if len(result.Matches) == 0 {
355+
builder.WriteString("Keine passenden Server gefunden.")
356+
return builder.String()
357+
}
358+
359+
for i, match := range result.Matches {
360+
if i > 0 {
361+
builder.WriteString("\n")
362+
}
363+
builder.WriteString(fmt.Sprintf("Host: %s\n", match.Host))
364+
builder.WriteString(match.Result.String())
365+
builder.WriteString("\n")
366+
}
367+
return builder.String()
368+
}

0 commit comments

Comments
 (0)