From 4550f2a2a7471eea7dcbd61fd7f19e4d41421d50 Mon Sep 17 00:00:00 2001 From: Rolf Offermanns Date: Fri, 8 Aug 2025 11:03:18 +0200 Subject: [PATCH] feat: Add hostname from dns client to monitor and tui --- cmd/monitor.go | 10 ++++++++-- internal/api/server.go | 1 + internal/dns/server.go | 22 ++++++++++++++++++++++ internal/tui/tui.go | 16 +++++++++++----- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/cmd/monitor.go b/cmd/monitor.go index da03025..7aa8e8e 100644 --- a/cmd/monitor.go +++ b/cmd/monitor.go @@ -47,7 +47,7 @@ Make sure the resolver is running before using this command.`, } fmt.Printf("Last %d DNS requests:\n\n", len(queries[start:])) - fmt.Printf("%-40s %-10s %-20s %s\n", "Domain", "Status", "Time", "Blocked") + fmt.Printf("%-40s %-27s %-10s %-20s %s\n", "Domain", "Client", "Status", "Time", "Blocked") fmt.Println(string(make([]byte, 80))) for _, query := range queries[start:] { @@ -68,7 +68,13 @@ Make sure the resolver is running before using this command.`, domain = domain[:35] + "..." } - fmt.Printf("%-40s %-10s %-20s %s\n", domain, status, timeStr, blockedStr) + // Truncate hostname if too long + dnsClient := query.Client + if len(dnsClient) > 25 { + dnsClient = dnsClient[:22] + "..." + } + + fmt.Printf("%-40s %-27s %-10s %-20s %s\n", domain, dnsClient, status, timeStr, blockedStr) } fmt.Printf("\nTotal queries: %d\n", len(queries)) diff --git a/internal/api/server.go b/internal/api/server.go index 6595545..2479676 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -13,6 +13,7 @@ import ( ) type DNSQuery struct { + Client string `json:"client"` Domain string `json:"domain"` Timestamp time.Time `json:"timestamp"` Blocked bool `json:"blocked"` diff --git a/internal/dns/server.go b/internal/dns/server.go index f520830..3af6288 100644 --- a/internal/dns/server.go +++ b/internal/dns/server.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "log" + "net" "os" "path/filepath" "regexp" @@ -70,6 +71,25 @@ func NewServerWithPort(cfg *config.Config, apiServer *api.Server, port string) * } } +func resolveHost(addr string) string { + // Extract host part from "ip:port" + host, _, err := net.SplitHostPort(addr) + if err != nil { + // addr might just be an IP without port + host = addr + } + + // Do reverse DNS lookup + names, err := net.LookupAddr(host) + if err != nil || len(names) == 0 { + return host // fallback to IP + } + + // Remove trailing dot from hostname + hostname := strings.TrimSuffix(names[0], ".") + return hostname +} + // wildcardToRegex converts a wildcard pattern to a regex pattern // Examples: // @@ -325,7 +345,9 @@ func (s *Server) handleRequest(w dns.ResponseWriter, r *dns.Msg) { // Add to API server if available if s.apiServer != nil { + clientHostname := resolveHost(w.RemoteAddr().String()) query := api.DNSQuery{ + Client: clientHostname, Domain: domain, Timestamp: time.Now(), Blocked: blocked, diff --git a/internal/tui/tui.go b/internal/tui/tui.go index 405a8b8..49c6aeb 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -795,8 +795,8 @@ Make sure the resolver is running with 'sinkzone resolver'` } // Header - header := fmt.Sprintf("%-40s %-20s %-10s\n", "Domain", "Time", "Status") - header += strings.Repeat("-", 70) + "\n" + header := fmt.Sprintf("%-40s %-27s %-20s %-10s\n", "Domain", "Client", "Time", "Status") + header += strings.Repeat("-", 97) + "\n" // Table rows var rows []string @@ -814,12 +814,18 @@ Make sure the resolver is running with 'sinkzone resolver'` domain = domain[:35] + "..." } + // Truncate hostname if too long + dnsClient := query.Client + if len(dnsClient) > 25 { + dnsClient = dnsClient[:22] + "..." + } + // Check if this row is selected // Since we display newest first (reversed), map cursor position isSelected := i == m.monitoring.tableCursor recentlyChanged := query.Domain == m.lastChangedDomain && time.Since(m.lastChangeTime) < 2*time.Second - row := formatTableRow(domain, query.Timestamp, status, isSelected, recentlyChanged) + row := formatTableRow(domain, dnsClient, query.Timestamp, status, isSelected, recentlyChanged) rows = append(rows, row) } @@ -903,8 +909,8 @@ func formatAllowlistRow(domain string, domainType string, status string, isSelec return row } -func formatTableRow(domain string, timestamp time.Time, status string, isSelected bool, recentlyChanged bool) string { - row := fmt.Sprintf("%-40s %-20s %-10s", domain, timestamp.Format("15:04:05"), status) +func formatTableRow(domain string, dnsClient string, timestamp time.Time, status string, isSelected bool, recentlyChanged bool) string { + row := fmt.Sprintf("%-40s %-27s %-20s %-10s", domain, dnsClient, timestamp.Format("15:04:05"), status) if isSelected && recentlyChanged { // Combined state: selected and recently changed - use a distinct color