mirror of
https://github.com/lukaszraczylo/lolcathost.git
synced 2026-06-05 23:29:18 +00:00
143 lines
3.8 KiB
Go
143 lines
3.8 KiB
Go
// Package daemon provides DNS cache flushing functionality.
|
|
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"runtime"
|
|
)
|
|
|
|
// DNSFlusher handles DNS cache flushing.
|
|
type DNSFlusher struct {
|
|
method FlushMethod
|
|
}
|
|
|
|
// FlushMethod defines the DNS flush method to use.
|
|
type FlushMethod string
|
|
|
|
const (
|
|
FlushMethodAuto FlushMethod = "auto"
|
|
FlushMethodDscacheutil FlushMethod = "dscacheutil"
|
|
FlushMethodKillall FlushMethod = "killall"
|
|
FlushMethodBoth FlushMethod = "both"
|
|
FlushMethodSystemd FlushMethod = "systemd"
|
|
FlushMethodNscd FlushMethod = "nscd"
|
|
)
|
|
|
|
// NewDNSFlusher creates a new DNS flusher.
|
|
func NewDNSFlusher(method FlushMethod) *DNSFlusher {
|
|
return &DNSFlusher{method: method}
|
|
}
|
|
|
|
// Flush flushes the DNS cache using the configured method.
|
|
func (f *DNSFlusher) Flush() error {
|
|
method := f.method
|
|
if method == FlushMethodAuto || method == "" {
|
|
method = f.detectMethod()
|
|
}
|
|
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
return f.flushDarwin(method)
|
|
case "linux":
|
|
return f.flushLinux(method)
|
|
default:
|
|
return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
|
|
}
|
|
}
|
|
|
|
func (f *DNSFlusher) detectMethod() FlushMethod {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
return FlushMethodBoth
|
|
case "linux":
|
|
// Check for systemd-resolve first
|
|
if _, err := exec.LookPath("systemd-resolve"); err == nil {
|
|
return FlushMethodSystemd
|
|
}
|
|
if _, err := exec.LookPath("resolvectl"); err == nil {
|
|
return FlushMethodSystemd
|
|
}
|
|
// Fall back to nscd
|
|
if _, err := exec.LookPath("nscd"); err == nil {
|
|
return FlushMethodNscd
|
|
}
|
|
return FlushMethodAuto
|
|
default:
|
|
return FlushMethodAuto
|
|
}
|
|
}
|
|
|
|
func (f *DNSFlusher) flushDarwin(method FlushMethod) error {
|
|
var errs []error
|
|
|
|
switch method {
|
|
case FlushMethodDscacheutil:
|
|
if err := runCommand("dscacheutil", "-flushcache"); err != nil {
|
|
return fmt.Errorf("dscacheutil failed: %w", err)
|
|
}
|
|
case FlushMethodKillall:
|
|
if err := runCommand("killall", "-HUP", "mDNSResponder"); err != nil {
|
|
return fmt.Errorf("killall mDNSResponder failed: %w", err)
|
|
}
|
|
case FlushMethodBoth:
|
|
if err := runCommand("dscacheutil", "-flushcache"); err != nil {
|
|
errs = append(errs, fmt.Errorf("dscacheutil failed: %w", err))
|
|
}
|
|
if err := runCommand("killall", "-HUP", "mDNSResponder"); err != nil {
|
|
errs = append(errs, fmt.Errorf("killall mDNSResponder failed: %w", err))
|
|
}
|
|
if len(errs) == 2 {
|
|
return fmt.Errorf("all DNS flush methods failed: %v, %v", errs[0], errs[1])
|
|
}
|
|
default:
|
|
// Auto - try both
|
|
_ = runCommand("dscacheutil", "-flushcache")
|
|
_ = runCommand("killall", "-HUP", "mDNSResponder")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (f *DNSFlusher) flushLinux(method FlushMethod) error {
|
|
switch method {
|
|
case FlushMethodSystemd:
|
|
// Try resolvectl first (newer), then systemd-resolve (older)
|
|
if err := runCommand("resolvectl", "flush-caches"); err != nil {
|
|
if err := runCommand("systemd-resolve", "--flush-caches"); err != nil {
|
|
return fmt.Errorf("systemd DNS flush failed: %w", err)
|
|
}
|
|
}
|
|
case FlushMethodNscd:
|
|
// Try to restart nscd
|
|
if err := runCommand("nscd", "-i", "hosts"); err != nil {
|
|
// Try service restart as fallback
|
|
if err := runCommand("service", "nscd", "restart"); err != nil {
|
|
return fmt.Errorf("nscd flush failed: %w", err)
|
|
}
|
|
}
|
|
default:
|
|
// Auto - try all methods
|
|
// Try systemd first
|
|
if err := runCommand("resolvectl", "flush-caches"); err == nil {
|
|
return nil
|
|
}
|
|
if err := runCommand("systemd-resolve", "--flush-caches"); err == nil {
|
|
return nil
|
|
}
|
|
// Try nscd
|
|
if err := runCommand("nscd", "-i", "hosts"); err == nil {
|
|
return nil
|
|
}
|
|
// On many Linux systems, no explicit flush is needed as /etc/hosts is read directly
|
|
// So we return nil here
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func runCommand(name string, args ...string) error {
|
|
cmd := exec.Command(name, args...)
|
|
return cmd.Run()
|
|
}
|