Skip to content

Commit b0226d1

Browse files
authored
fix: dns resolution taking long and add caching options (#8)
1 parent 1021ba1 commit b0226d1

File tree

13 files changed

+1302
-67
lines changed

13 files changed

+1302
-67
lines changed

README.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,20 @@ shortcut flags work on all commands:
167167
-e, --established established connections
168168
-4, --ipv4 ipv4 only
169169
-6, --ipv6 ipv6 only
170-
-n, --numeric no dns resolution
171170
```
172171

172+
## resolution
173+
174+
dns and service name resolution options:
175+
176+
```
177+
--resolve-addrs resolve ip addresses to hostnames (default: true)
178+
--resolve-ports resolve port numbers to service names
179+
--no-cache disable dns caching (force fresh lookups)
180+
```
181+
182+
dns lookups are performed in parallel and cached for performance. use `--no-cache` to bypass the cache for debugging or when addresses change frequently.
183+
173184
for more specific filtering, use `key=value` syntax with `ls`:
174185

175186
```bash
@@ -208,8 +219,19 @@ optional config file at `~/.config/snitch/snitch.toml`:
208219

209220
```toml
210221
[defaults]
211-
numeric = false
212-
theme = "auto"
222+
numeric = false # disable name resolution
223+
dns_cache = true # cache dns lookups (set to false to disable)
224+
theme = "auto" # color theme: auto, dark, light, mono
225+
```
226+
227+
### environment variables
228+
229+
```bash
230+
SNITCH_THEME=dark # set default theme
231+
SNITCH_RESOLVE=0 # disable dns resolution
232+
SNITCH_DNS_CACHE=0 # disable dns caching
233+
SNITCH_NO_COLOR=1 # disable color output
234+
SNITCH_CONFIG=/path/to # custom config file path
213235
```
214236

215237
## requirements

cmd/ls.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ var (
3030
sortBy string
3131
fields string
3232
colorMode string
33-
resolveAddrs bool
34-
resolvePorts bool
3533
plainOutput bool
3634
)
3735

@@ -400,10 +398,9 @@ func init() {
400398
lsCmd.Flags().StringVarP(&sortBy, "sort", "s", cfg.Defaults.SortBy, "Sort by column (e.g., pid:desc)")
401399
lsCmd.Flags().StringVarP(&fields, "fields", "f", strings.Join(cfg.Defaults.Fields, ","), "Comma-separated list of fields to show")
402400
lsCmd.Flags().StringVar(&colorMode, "color", cfg.Defaults.Color, "Color mode (auto, always, never)")
403-
lsCmd.Flags().BoolVar(&resolveAddrs, "resolve-addrs", !cfg.Defaults.Numeric, "Resolve IP addresses to hostnames")
404-
lsCmd.Flags().BoolVar(&resolvePorts, "resolve-ports", false, "Resolve port numbers to service names")
405401
lsCmd.Flags().BoolVarP(&plainOutput, "plain", "p", false, "Plain output (parsable, no styling)")
406402

407-
// shared filter flags
403+
// shared flags
408404
addFilterFlags(lsCmd)
405+
addResolutionFlags(lsCmd)
409406
}

cmd/root.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,8 @@ func init() {
4545
cfg := config.Get()
4646
rootCmd.Flags().StringVar(&topTheme, "theme", cfg.Defaults.Theme, "Theme for TUI (see 'snitch themes')")
4747
rootCmd.Flags().DurationVarP(&topInterval, "interval", "i", 0, "Refresh interval (default 1s)")
48-
rootCmd.Flags().BoolVar(&topResolveAddrs, "resolve-addrs", !cfg.Defaults.Numeric, "Resolve IP addresses to hostnames")
49-
rootCmd.Flags().BoolVar(&topResolvePorts, "resolve-ports", false, "Resolve port numbers to service names")
5048

51-
// shared filter flags for root command
49+
// shared flags for root command
5250
addFilterFlags(rootCmd)
51+
addResolutionFlags(rootCmd)
5352
}

cmd/runtime.go

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import (
44
"fmt"
55
"github.com/karol-broda/snitch/internal/collector"
66
"github.com/karol-broda/snitch/internal/color"
7+
"github.com/karol-broda/snitch/internal/config"
8+
"github.com/karol-broda/snitch/internal/resolver"
79
"strconv"
810
"strings"
911

1012
"github.com/spf13/cobra"
1113
)
1214

1315
// Runtime holds the shared state for all commands.
14-
// it handles common filter logic, fetching, and filtering connections.
16+
// it handles common filter logic, fetching, filtering, and resolution.
1517
type Runtime struct {
1618
// filter options built from flags and args
1719
Filters collector.FilterOptions
@@ -23,6 +25,7 @@ type Runtime struct {
2325
ColorMode string
2426
ResolveAddrs bool
2527
ResolvePorts bool
28+
NoCache bool
2629
}
2730

2831
// shared filter flags - used by all commands
@@ -35,6 +38,13 @@ var (
3538
filterIPv6 bool
3639
)
3740

41+
// shared resolution flags - used by all commands
42+
var (
43+
resolveAddrs bool
44+
resolvePorts bool
45+
noCache bool
46+
)
47+
3848
// BuildFilters constructs FilterOptions from command args and shortcut flags.
3949
func BuildFilters(args []string) (collector.FilterOptions, error) {
4050
filters, err := ParseFilterArgs(args)
@@ -77,6 +87,12 @@ func FetchConnections(filters collector.FilterOptions) ([]collector.Connection,
7787
func NewRuntime(args []string, colorMode string) (*Runtime, error) {
7888
color.Init(colorMode)
7989

90+
cfg := config.Get()
91+
92+
// configure resolver with cache setting (flag overrides config)
93+
effectiveNoCache := noCache || !cfg.Defaults.DNSCache
94+
resolver.SetNoCache(effectiveNoCache)
95+
8096
filters, err := BuildFilters(args)
8197
if err != nil {
8298
return nil, fmt.Errorf("failed to parse filters: %w", err)
@@ -87,13 +103,30 @@ func NewRuntime(args []string, colorMode string) (*Runtime, error) {
87103
return nil, fmt.Errorf("failed to fetch connections: %w", err)
88104
}
89105

90-
return &Runtime{
106+
rt := &Runtime{
91107
Filters: filters,
92108
Connections: connections,
93109
ColorMode: colorMode,
94110
ResolveAddrs: resolveAddrs,
95111
ResolvePorts: resolvePorts,
96-
}, nil
112+
NoCache: effectiveNoCache,
113+
}
114+
115+
// pre-warm dns cache by resolving all addresses in parallel
116+
if resolveAddrs {
117+
rt.PreWarmDNS()
118+
}
119+
120+
return rt, nil
121+
}
122+
123+
// PreWarmDNS resolves all connection addresses in parallel to warm the cache.
124+
func (r *Runtime) PreWarmDNS() {
125+
addrs := make([]string, 0, len(r.Connections)*2)
126+
for _, c := range r.Connections {
127+
addrs = append(addrs, c.Laddr, c.Raddr)
128+
}
129+
resolver.ResolveAddrsParallel(addrs)
97130
}
98131

99132
// SortConnections sorts the runtime's connections in place.
@@ -201,3 +234,11 @@ func addFilterFlags(cmd *cobra.Command) {
201234
cmd.Flags().BoolVarP(&filterIPv6, "ipv6", "6", false, "Only show IPv6 connections")
202235
}
203236

237+
// addResolutionFlags adds the common resolution flags to a command.
238+
func addResolutionFlags(cmd *cobra.Command) {
239+
cfg := config.Get()
240+
cmd.Flags().BoolVar(&resolveAddrs, "resolve-addrs", !cfg.Defaults.Numeric, "Resolve IP addresses to hostnames")
241+
cmd.Flags().BoolVar(&resolvePorts, "resolve-ports", false, "Resolve port numbers to service names")
242+
cmd.Flags().BoolVar(&noCache, "no-cache", !cfg.Defaults.DNSCache, "Disable DNS caching (force fresh lookups)")
243+
}
244+

0 commit comments

Comments
 (0)