Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement whoami.v4.powerdns.org #47

Merged
merged 2 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion dnsserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ func NewDNSConfig() *DNSConfig {
}
}

// Clone clones a [DNSConfig].
func (dc *DNSConfig) Clone() *DNSConfig {
defer dc.mu.Unlock()
dc.mu.Lock()
out := NewDNSConfig()
for key, value := range dc.r {
out.r[key] = &DNSRecord{
A: append([]net.IP{}, value.A...),
CNAME: value.CNAME,
}
}
return out
}

// ErrNotIPAddress indicates that a string is not a serialized IP address.
var ErrNotIPAddress = errors.New("netem: not a valid IP address")

Expand Down Expand Up @@ -132,6 +146,21 @@ func (dc *DNSConfig) Lookup(name string) (*DNSRecord, bool) {
return record, found
}

func dnsConfigWithWhoami(config *DNSConfig, endpoint net.Addr) *DNSConfig {
// make sure we operate on a copy
config = config.Clone()

// extract the endpoint address
ipAddr, _, err := net.SplitHostPort(endpoint.String())
if err != nil {
return config
}

// add whoami.v4.powerdns.org record
_ = config.AddRecord("whoami.v4.powerdns.org", "", ipAddr)
return config
}

// dnsServerWorker is the [DNSServer] worker.
func dnsServerWorker(
logger Logger,
Expand All @@ -156,7 +185,7 @@ func dnsServerWorker(
}
rawQuery := buffer[:count]

rawResponse, err := DNSServerRoundTrip(config, rawQuery)
rawResponse, err := DNSServerRoundTrip(dnsConfigWithWhoami(config, addr), rawQuery)
if err != nil {
logger.Warnf("netem: dnsServerRoundTrip: %s", err.Error())
continue
Expand Down
21 changes: 21 additions & 0 deletions dnsserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,25 @@ func TestDNSConfig(t *testing.T) {
})
})
})

t.Run("we can clone a DNSConfig", func(t *testing.T) {
config := NewDNSConfig()
config.AddRecord("www.example.com", "", "130.192.91.211")
other := config.Clone()
config.RemoveRecord("www.example.com")
if _, good := config.Lookup("www.example.com"); good {
t.Fatal("expected record to be missing")
}
record, good := other.Lookup("www.example.com")
if !good {
t.Fatal("expected to see record")
}
expect := &DNSRecord{
A: []net.IP{net.IPv4(130, 192, 91, 211)},
CNAME: "",
}
if diff := cmp.Diff(expect, record); diff != "" {
t.Fatal(diff)
}
})
}
61 changes: 61 additions & 0 deletions example_star_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package netem_test

import (
"context"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -114,3 +115,63 @@ func Example_starTopologyHTTPSAndDNS() {
// Bonsoir, Elliot!
//
}

// This example shows how DNS servers implement whoami.v4.powerdns.org
func Example_starTopologyDNSWhoami() {
// Create a star topology for our hosts.
topology := netem.MustNewStarTopology(&netem.NullLogger{})
defer topology.Close()

// Add client stack to topology. Note that we don't need to
// close the clientStack: the topology will do that.
clientStack, err := topology.AddHost(
"130.192.91.211", // host IP address
"8.8.8.8", // host DNS resolver IP address
&netem.LinkConfig{}, // link with no PLR, RTT, DPI
)
if err != nil {
log.Fatal(err)
}

// Add DNS server stack to topology.
dnsServerStack, err := topology.AddHost(
"8.8.8.8",
"8.8.8.8", // this host is its own DNS resolver
&netem.LinkConfig{},
)
if err != nil {
log.Fatal(err)
}

// spawn a DNS server with empty configuration.
dnsConfig := netem.NewDNSConfig()
dnsServer, err := netem.NewDNSServer(
&netem.NullLogger{},
dnsServerStack,
"8.8.8.8",
dnsConfig,
)
if err != nil {
log.Fatal(err)
}
defer dnsServer.Close()

// create the DNS query to use
query := netem.NewDNSRequestA("whoami.v4.powerdns.org")

// issue a DNS request to the server
response, err := netem.DNSRoundTrip(context.Background(), clientStack, "8.8.8.8", query)
if err != nil {
log.Fatal(err)
}

// parse the DNS response
addrs, _, err := netem.DNSParseResponse(query, response)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", addrs)
// Output:
// [130.192.91.211]
//
}
Loading