Skip to content

Commit

Permalink
Add --dry-with-dhcp option
Browse files Browse the repository at this point in the history
  • Loading branch information
rtpt-erikgeiser committed May 8, 2023
1 parent 8dbbb01 commit 124d115
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 30 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ For more information, run `pretender --help`.
- If you are not sure which interface to choose (especially on Windows), list
all interfaces with names and addresses using `--interfaces`
- If you want to exclude hosts from local name resolution spoofing, make sure to
also exclude their IPv6 addresses or use `--no-ipv6-lnr`/`main.vendorNoIPv6LNR`
also exclude their IPv6 addresses or use
`--no-ipv6-lnr`/`main.vendorNoIPv6LNR`
- DHCPv6 messages usually contain a FQDN option (which can also sometimes
contain a hostname which is not a FQDN). This option is used to filter out
messages by hostname (`--spoof-for`/`--dont-spoof-for`). You can decide what
Expand All @@ -109,7 +110,8 @@ For more information, run `pretender --help`.
- By default, in order to limit disruption during a DHCPv6 DNS Takeover, the
option `--delegate-ignored-to <DNS server>` can be used to delegate ignored
queries to a legitimate DNS server.

- The option `--dry-with-dhcp` can be combined with `--delegate-ignored-to` to
monitor the name resolution queries in the network without disruption.
---

## Building and Vendoring
Expand Down Expand Up @@ -160,6 +162,7 @@ vendorIgnoreDHCPv6NoFQDN
vendorDelegateIgnoredTo
vendorDontSendEmptyReplies
vendorDryMode
vendorDryWithDHCPMode
vendorTTL
vendorLeaseLifetime
vendorRARouterLifetime
Expand Down
55 changes: 35 additions & 20 deletions cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type Config struct {
DelegateIgnoredTo string
DontSendEmptyReplies bool
DryMode bool
DryWithDHCPv6 bool
DryWithDHCPv6Mode bool

StopAfter time.Duration
Verbose bool
Expand Down Expand Up @@ -88,13 +88,17 @@ func (c Config) PrintSummary() { //nolint:cyclop

switch {
case c.DryMode:
var raNotice string

raNotice := ""
if !c.NoRA && !c.NoDHCPv6DNSTakeover && !c.NoDHCPv6 {
raNotice = " (RA is still enabled)"
}

fmt.Println("Dry Mode: DHCPv6 and name resolution queries will not be answered" + raNotice)
drySubject := "DHCPv6 and name resolution queries"
if c.DryWithDHCPv6Mode {
drySubject = "Name resolution queries"
}

fmt.Printf("Dry Mode: %s will not be answered%s\n", drySubject, raNotice)
default:
if len(c.Spoof) != 0 {
fmt.Println("Answering queries for: " + joinDomains(c.Spoof))
Expand Down Expand Up @@ -128,7 +132,27 @@ func (c Config) PrintSummary() { //nolint:cyclop
fmt.Println()
}

//nolint:forbidigo,cyclop,maintidx
func (c *Config) setRedundantOptions() {
if c.DryWithDHCPv6Mode {
c.DryMode = true
}

if c.NoDNS && c.NoDHCPv6 {
c.NoDHCPv6DNSTakeover = true
}

if c.NoMDNS && c.NoLLMNR && c.NoNetBIOS {
c.NoLocalNameResolution = true
}

if c.NoLocalNameResolution {
c.NoNetBIOS = true
c.NoLLMNR = true
c.NoMDNS = true
}
}

//nolint:forbidigo,cyclop
func configFromCLI() (config Config, logger *Logger, err error) {
var (
interfaceName string
Expand Down Expand Up @@ -178,8 +202,11 @@ func configFromCLI() (config Config, logger *Logger, err error) {
pflag.BoolVar(&config.DontSendEmptyReplies, "dont-send-empty-replies", defaultDontSendEmptyReplies,
"Don't reply at all to ignored DNS queries or failed delegated\nqueries instead of sending an empty reply")
pflag.BoolVar(&config.DryMode, "dry", defaultDryMode,
"Do not spoof name resolution at all, only log queries (does not disable\nRA but it"+
" can be combined with --no-ra)")
"Do not answer DHCPv6 or any name resolution queries, only log them\n(does not disable RA but it "+
"can be combined with --no-ra)")
pflag.BoolVar(&config.DryWithDHCPv6Mode, "dry-with-dhcp", defaultDryWithDHCPMode,
"Send RA and answer DHCPv6 queries but only log name resolution\nqueries (can be"+
" combined with --delegate-ignored-to, takes\nprecedence over --dry)")

pflag.DurationVarP(&config.TTL, "ttl", "t", defaultTTL, "Time to live for name resolution responses")
pflag.DurationVar(&config.LeaseLifetime, "lease-lifetime", defaultLeaseLifetime, "DHCPv6 IP lease lifetime")
Expand Down Expand Up @@ -216,19 +243,7 @@ func configFromCLI() (config Config, logger *Logger, err error) {
stdErr = os.Stdout
}

if config.NoDNS && config.NoDHCPv6 {
config.NoDHCPv6DNSTakeover = true
}

if config.NoMDNS && config.NoLLMNR && config.NoNetBIOS {
config.NoLocalNameResolution = true
}

if config.NoLocalNameResolution {
config.NoNetBIOS = true
config.NoLLMNR = true
config.NoMDNS = true
}
config.setRedundantOptions()

if printVersion {
fmt.Println(longVersion())
Expand Down
2 changes: 2 additions & 0 deletions defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var (
vendorDelegateIgnoredTo = ""
vendorDontSendEmptyReplies = ""
vendorDryMode = ""
vendorDryWithDHCPMode = ""

vendorTTL = ""
vendorLeaseLifetime = ""
Expand Down Expand Up @@ -81,6 +82,7 @@ var (
defaultDelegateIgnoredTo = vendorDelegateIgnoredTo
defaultDontSendEmptyReplies = forceBool(vendorDontSendEmptyReplies, false)
defaultDryMode = forceBool(vendorDryMode, false)
defaultDryWithDHCPMode = forceBool(vendorDryWithDHCPMode, false)

defaultTTL = forceDuration(vendorTTL, dnsDefaultTTL)
defaultLeaseLifetime = forceDuration(vendorLeaseLifetime, dhcpv6DefaultValidLifetime)
Expand Down
2 changes: 1 addition & 1 deletion filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func shouldRespondToNameResolutionQuery(config Config, host string, queryType ui
}

func shouldRespondToDHCP(config Config, from peerInfo) (bool, string) {
if config.DryMode {
if config.DryMode && !config.DryWithDHCPv6Mode {
return false, "dry mode"
}

Expand Down
44 changes: 37 additions & 7 deletions filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func TestFilterNameResolutionQuery(t *testing.T) { //nolint:maintidx,cyclop
DontSpoof []string
SpoofTypes []string
DryMode bool
DryWithDHCPv6Mode bool
NoRelayIPv4Configured bool
NoRelayIPv6Configured bool

Expand Down Expand Up @@ -53,6 +54,13 @@ func TestFilterNameResolutionQuery(t *testing.T) { //nolint:maintidx,cyclop
From: someIP,
ShouldRespond: false,
},
{
TestName: "dry with dhcp",
Host: "foo",
DryWithDHCPv6Mode: true,
From: someIP,
ShouldRespond: false,
},
{
Host: "foo",
Spoof: []string{"foo"},
Expand Down Expand Up @@ -332,15 +340,18 @@ func TestFilterNameResolutionQuery(t *testing.T) { //nolint:maintidx,cyclop
}

cfg := Config{
SpoofFor: asHostMatchers(testCase.SpoofFor, defaultLookupTimeout),
DontSpoofFor: asHostMatchers(testCase.DontSpoofFor, defaultLookupTimeout),
Spoof: testCase.Spoof,
DontSpoof: testCase.DontSpoof,
DryMode: testCase.DryMode,
SpoofTypes: types,
SOAHostname: "test",
SpoofFor: asHostMatchers(testCase.SpoofFor, defaultLookupTimeout),
DontSpoofFor: asHostMatchers(testCase.DontSpoofFor, defaultLookupTimeout),
Spoof: testCase.Spoof,
DontSpoof: testCase.DontSpoof,
DryMode: testCase.DryMode,
DryWithDHCPv6Mode: testCase.DryWithDHCPv6Mode,
SpoofTypes: types,
SOAHostname: "test",
}

cfg.setRedundantOptions()

switch {
case !testCase.NoRelayIPv4Configured:
cfg.RelayIPv4 = relayIPv4
Expand Down Expand Up @@ -376,6 +387,7 @@ func TestFilterDHCP(t *testing.T) {
DontSpoofFor []string
IgnoreDHCPv6NoFQDN bool
DryMode bool
DryWithDHCPv6Mode bool

PeerIP net.IP
PeerHostnames []string
Expand All @@ -395,6 +407,21 @@ func TestFilterDHCP(t *testing.T) {
PeerHostnames: []string{"foo"},
ShouldRespond: false,
},
{
TestName: "dry with dhcp",
DryWithDHCPv6Mode: true,
PeerIP: someIP,
PeerHostnames: []string{"foo"},
ShouldRespond: true,
},
{
TestName: "dry and drywith dhcp",
DryMode: true,
DryWithDHCPv6Mode: true,
PeerIP: someIP,
PeerHostnames: []string{"foo"},
ShouldRespond: true,
},
{
TestName: "dry+spooffor",
SpoofFor: []string{someIP.String(), "foo"},
Expand Down Expand Up @@ -469,9 +496,12 @@ func TestFilterDHCP(t *testing.T) {
SpoofFor: asHostMatchers(testCase.SpoofFor, defaultLookupTimeout),
DontSpoofFor: asHostMatchers(testCase.DontSpoofFor, defaultLookupTimeout),
DryMode: testCase.DryMode,
DryWithDHCPv6Mode: testCase.DryWithDHCPv6Mode,
IgnoreDHCPv6NoFQDN: testCase.IgnoreDHCPv6NoFQDN,
}

cfg.setRedundantOptions()

shouldRespond, _ := shouldRespondToDHCP(cfg,
peerInfo{IP: testCase.PeerIP, Hostnames: testCase.PeerHostnames})
if shouldRespond != testCase.ShouldRespond {
Expand Down

0 comments on commit 124d115

Please sign in to comment.