Skip to content

Commit

Permalink
Add implementation of ordindary DNS provider for query plain old DNS …
Browse files Browse the repository at this point in the history
…records
  • Loading branch information
prologic committed Aug 15, 2022
1 parent c261e06 commit 82ca5df
Show file tree
Hide file tree
Showing 5 changed files with 267 additions and 6 deletions.
13 changes: 7 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
cmd/discover/discover
.terraform/
.terraform.tfstate.lock.info
terraform.tfstate
terraform.tfstate.backup
terraform.tfvars
*~
*.bak
terraform.*
.terraform.*

/discover
/cmd/discover/discover
2 changes: 2 additions & 0 deletions discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/hashicorp/go-discover/provider/aws"
"github.com/hashicorp/go-discover/provider/azure"
"github.com/hashicorp/go-discover/provider/digitalocean"
"github.com/hashicorp/go-discover/provider/dns"
"github.com/hashicorp/go-discover/provider/gce"
"github.com/hashicorp/go-discover/provider/linode"
"github.com/hashicorp/go-discover/provider/mdns"
Expand Down Expand Up @@ -49,6 +50,7 @@ var Providers = map[string]Provider{
"aws": &aws.Provider{},
"azure": &azure.Provider{},
"digitalocean": &digitalocean.Provider{},
"dns": &dns.Provider{},
"gce": &gce.Provider{},
"linode": &linode.Provider{},
"mdns": &mdns.Provider{},
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443
github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62
github.com/linode/linodego v0.7.1
github.com/miekg/dns v1.0.14
github.com/mitchellh/go-homedir v1.1.0
github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2
github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c
Expand Down
106 changes: 106 additions & 0 deletions provider/dns/dns_provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Package dns provides node discovery via DNS.
package dns

import (
"fmt"
"io/ioutil"
"log"
"net"
"strconv"
"time"

"github.com/miekg/dns"
)

// Provider implements the Provider interface.
type Provider struct{}

// Help returns help information for the DNS package.
func (p *Provider) Help() string {
return `DNS:
provider: "dns"
query: The DNS query to lookup. Required.
server: The DNS server to query. Default "8.8.8.8" (Google DNS).
port: The DNS port to use. Default: "53" (standard DNS port).
timeout: The mDNS lookup timeout. Default "5s" (five seconds).
`
}

// Addrs returns discovered addresses for the mDNS package.
func (p *Provider) Addrs(args map[string]string, l *log.Logger) ([]string, error) {
var err error

// default to null logger
if l == nil {
l = log.New(ioutil.Discard, "", 0)
}

// validate and set service record
if args["query"] == "" {
return nil, fmt.Errorf("discover-dns: Query not provided." +
" Please specify a valid dns query for the DNS lookup.")
}

var server string
// validate and set server
if args["server"] != "" {
server = args["server"]
} else {
server = "8.8.8.8"
}

var port int
// validate and set port
if args["port"] != "" {
if port, err = strconv.Atoi(args["port"]); err != nil {
return nil, fmt.Errorf("discover-dns: Failed to parse port: %s", err)
}
} else {
port = 53
}

var timeout time.Duration
// validate and set timeout
if args["timeout"] != "" {
if timeout, err = time.ParseDuration(args["timeout"]); err != nil {
return nil, fmt.Errorf("discover-dns: Failed to parse timeout: %s", err)
}
} else {
timeout = 5 * time.Second
}

var addrs []string

// lookup and return
m1 := new(dns.Msg)
m1.Id = dns.Id()
m1.RecursionDesired = true
m1.Question = make([]dns.Question, 1)
m1.Question[0] = dns.Question{args["query"], dns.TypeA, dns.ClassINET}

c := new(dns.Client)

laddr := net.UDPAddr{
IP: net.ParseIP("[::1]"),
Port: 0,
Zone: "",
}
c.Dialer = &net.Dialer{
Timeout: timeout,
LocalAddr: &laddr,
}
raddr := fmt.Sprintf("%s:%d", server, port)
in, _, err := c.Exchange(m1, raddr)
if err != nil {
return nil, fmt.Errorf("discover-mdns: Failed to process query: %s", err)
}

for _, answer := range in.Answer {
if t, ok := answer.(*dns.A); ok {
addrs = append(addrs, t.A.String())
}
}

return addrs, err
}
151 changes: 151 additions & 0 deletions provider/dns/dns_provider_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package dns_test

import (
"fmt"
"log"
"os"
"testing"

"github.com/miekg/dns"

discover "github.com/hashicorp/go-discover"
provider "github.com/hashicorp/go-discover/provider/dns"
)

const (
testService = "test-service"
)

var (
testAddresses = []string{"127.0.0.1"}
)

func newTestServer() (*dns.Server, error) {
var rr []dns.RR

for _, testAddress := range testAddresses {
a, _ := dns.NewRR(fmt.Sprintf("tasks.%s. IN A %s", testService, testAddress))
rr = append(rr, a)
}

server := &dns.Server{Addr: ":5300", Net: "udp"}
go server.ListenAndServe()
dns.HandleFunc(fmt.Sprintf("tasks.%s.", testService), func(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetReply(r)
m.Insert(rr)
w.WriteMsg(m)
})

return server, nil
}

func TestDiscover(t *testing.T) {
type testCases []struct {
desc string
args discover.Config
fail bool
addrs int
}

cases := testCases{
{
"valid config - no addresses",
discover.Config{
"provider": "dns",
"query": "tasks.fake-service",
"timeout": "1s",
"v6": "false",
"v4": "false",
},
false,
0,
},
{
"valid config - one address",
discover.Config{
"provider": "dns",
"query": "tasks.test-service",
"timeout": "10s",
"v6": "true",
"v4": "true",
},
false,
1,
},
{
"invalid config - missing query option",
discover.Config{
"provider": "dns",
"query": "",
"timeout": "1s",
"v6": "false",
"v4": "false",
},
true,
0,
},
{
"invalid config - bad timeout option",
discover.Config{
"provider": "dns",
"query": "tasks.fake-service",
"timeout": "1z",
"v6": "false",
"v4": "false",
},
true,
0,
},
{
"invalid config - bad v6 option",
discover.Config{
"provider": "dns",
"service": "tasks.fake-service",
"timeout": "1s",
"v6": "xxxx",
"v4": "false",
},
true,
0,
},
{
"invalid config - bad v4 option",
discover.Config{
"provider": "dns",
"service": "tasks.fake-service",
"timeout": "1s",
"v6": "false",
"v4": "xxxx",
},
true,
0,
},
}

p := &provider.Provider{}
l := log.New(os.Stderr, "", log.LstdFlags)

svr, err := newTestServer()
if err != nil {
t.Fatalf("Failed to start test server: %s", err.Error())
return
}
defer svr.Shutdown()

for idx, tc := range cases {
addrs, err := p.Addrs(tc.args, l)

if !tc.fail && err != nil {
t.Fatalf("FAIL [%d/%d] %s -> %s",
idx, len(cases), tc.desc, err)
}

if len(addrs) != tc.addrs {
t.Fatalf("FAIL [%d/%d] %s -> wrong addr count: expected %d / got %d",
idx, len(cases), tc.desc, tc.addrs, len(addrs))
}

t.Logf("PASS [%d/%d] %s", idx, len(cases), tc.desc)
}
}

0 comments on commit 82ca5df

Please sign in to comment.