Skip to content

Commit

Permalink
feat: implement whoami.v4.powerdns.org (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
bassosimone authored Feb 8, 2024
1 parent 14e4ce9 commit 608dcbc
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 1 deletion.
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]
//
}

0 comments on commit 608dcbc

Please sign in to comment.