]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
dnstap testing application
authorVicky Shrestha <vicky@geeks.net.np>
Thu, 8 Dec 2016 07:26:04 +0000 (23:26 -0800)
committerOndřej Surý <ondrej@sury.org>
Mon, 6 Mar 2017 11:48:21 +0000 (12:48 +0100)
tests/dnstap/src/dnstap-test/config [new file with mode: 0644]
tests/dnstap/src/dnstap-test/dnstap.mk [new file with mode: 0644]
tests/dnstap/src/dnstap-test/main.go [new file with mode: 0644]
tests/dnstap/src/dnstap-test/vendor/manifest [new file with mode: 0644]
tests/tests.mk

diff --git a/tests/dnstap/src/dnstap-test/config b/tests/dnstap/src/dnstap-test/config
new file mode 100644 (file)
index 0000000..df521a7
--- /dev/null
@@ -0,0 +1,10 @@
+verbose(true)
+modules = {
+       'hints',
+       dnstap = {
+               sockPath = "/tmp/dnstap.sock",
+       }
+}
+hints['fake1.localdomain'] = '1.2.3.4'
+hints['fake2.localdomain'] = '1.2.3.5'
+hints['fake3.localdomain'] = '1.2.3.6'
diff --git a/tests/dnstap/src/dnstap-test/dnstap.mk b/tests/dnstap/src/dnstap-test/dnstap.mk
new file mode 100644 (file)
index 0000000..f6dce71
--- /dev/null
@@ -0,0 +1,19 @@
+# dnstap tests
+GOPATH := $(abspath tests/dnstap)
+DNSTAP_TEST := dnstap-test
+DNSTAP_PATH := $(GOPATH)/src/$(DNSTAP_TEST)
+CONFIG := $(DNSTAP_PATH)/config
+CMD := daemon/kresd
+ZONES := "fake1.localdomain,fake2.localdomain,fake3.localdomain"
+TIMEOUT := 60s
+check-dnstap:
+       @echo "Checking dnstap functionality"
+       GOPATH=$(GOPATH) go get -u github.com/FiloSottile/gvt
+       cd $(DNSTAP_PATH) && $(GOPATH)/bin/gvt restore
+       GOPATH=$(GOPATH) go install $(DNSTAP_TEST)
+       $(GOPATH)/bin/$(DNSTAP_TEST) -c $(CONFIG) -cmd $(CMD) -q $(ZONES) -t $(TIMEOUT) 
+
+clean-dnstap:
+       rm -rf $(GOPATH)/bin $(GOPATH)/pkg
+
+.PHONY: check-dnstap clean-dnstap
diff --git a/tests/dnstap/src/dnstap-test/main.go b/tests/dnstap/src/dnstap-test/main.go
new file mode 100644 (file)
index 0000000..e7f62e1
--- /dev/null
@@ -0,0 +1,240 @@
+package main
+
+import (
+       "context"
+       "flag"
+       "fmt"
+       "github.com/cloudflare/dns"
+       dnstap "github.com/dnstap/golang-dnstap"
+       "github.com/golang/protobuf/proto"
+       "io"
+       "io/ioutil"
+       "log"
+       "net"
+       "os"
+       "os/exec"
+       "strings"
+       "time"
+)
+
+const (
+       kresdWorkDir = "/tmp/"
+)
+
+var (
+       kresdArgs = []string{
+               "-f1",
+               "-v",
+               "-q",
+       }
+)
+
+func qnameFromFrame(b []byte) (string, error) {
+       dt := &dnstap.Dnstap{}
+       var name string
+       if err := proto.Unmarshal(b, dt); err != nil {
+               log.Fatalf("dnstap proto.Unmarshal() failed: %s\n", err)
+               return name, err
+       }
+       m := dt.Message
+       if *m.Type != dnstap.Message_RESOLVER_RESPONSE {
+               return name, fmt.Errorf("Incorrect message type")
+       }
+       if m.QueryZone != nil {
+               sb, _, err := dns.UnpackDomainName(m.QueryZone, 0)
+               if err != nil {
+                       return name, err
+               }
+               name = fmt.Sprintf("%s", sb)
+       }
+       return name, nil
+}
+
+func listenOn() (net.Addr, *os.File, error) {
+       udpConn, err := net.ListenUDP("udp", &net.UDPAddr{
+               IP:   net.ParseIP("127.0.0.1"),
+               Port: 0,
+       })
+       if err != nil {
+               return nil, nil, err
+       }
+
+       file, err := udpConn.File()
+       if err != nil {
+               return nil, nil, err
+       }
+       return udpConn.LocalAddr(), file, nil
+}
+
+func runKresd(ctx context.Context, path, configFile string, grace time.Duration) (chan bool, error) {
+       ch := make(chan bool)
+       kresdArgs = append(kresdArgs, "-c"+configFile)
+       kresdArgs = append(kresdArgs, kresdWorkDir)
+       // we have 1 object in ExtraFiles with index 0
+       // child fd will be 3 + i = 3
+       kresdArgs = append(kresdArgs, "-S3")
+
+       file := ctx.Value("file").(*os.File)
+       debug := ctx.Value("debug").(bool)
+
+       cmd := exec.CommandContext(ctx, path, kresdArgs...)
+       cmd.ExtraFiles = []*os.File{file}
+
+       var stdout, stderr io.ReadCloser
+       var err error
+       if debug {
+               stdout, err = cmd.StdoutPipe()
+               if err != nil {
+                       log.Printf("stdoutpipe: %v\n", err)
+                       return ch, err
+               }
+
+               stderr, err = cmd.StderrPipe()
+               if err != nil {
+                       log.Printf("stderrpipe: %v\n", err)
+                       return ch, err
+               }
+       }
+
+       go func() {
+               status := false
+               defer func() {
+                       ch <- status // kresd done
+               }()
+               if err := cmd.Start(); err != nil {
+                       log.Printf("start: %v\n", err)
+                       return
+               }
+               time.Sleep(grace)
+               ch <- true // Started kresd
+
+               if debug {
+                       s, err := ioutil.ReadAll(stdout)
+                       if err != nil {
+                               log.Printf("readall: %v\n", err)
+                               return
+                       }
+                       if len(s) > 0 {
+                               fmt.Printf("stdout:\n%s\n", s)
+                       }
+
+                       s, err = ioutil.ReadAll(stderr)
+                       if err != nil {
+                               log.Printf("readall: %v\n", err)
+                               return
+                       }
+                       if len(s) > 0 {
+                               fmt.Printf("stderr:\n%s\n", s)
+                       }
+               }
+
+               if err := cmd.Wait(); err != nil && err.Error() != "signal: killed" {
+                       log.Printf("wait: %v\n", err)
+                       return
+               }
+               status = true
+       }()
+       return ch, nil
+}
+
+func main() {
+       var (
+               unixSocket = flag.String("u", "/tmp/dnstap.sock", "dnstap socket")
+               kresdPath  = flag.String("cmd", "daemon/kresd", "kresd path")
+               configFile = flag.String("c", "config", "config file")
+               qnames     = flag.String("q", ".", "list of comma separated zones")
+               grace      = flag.String("g", "1s", "Time to wait for daemon start")
+               timeout    = flag.String("t", "60s", "Test Timeout")
+               debug      = flag.Bool("d", false, "Debug")
+       )
+
+       flag.Parse()
+
+       kresdStartGracePeriod, err := time.ParseDuration(*grace)
+       if err != nil {
+               panic(err)
+       }
+
+       testTimeout, err := time.ParseDuration(*timeout)
+       if err != nil {
+               panic(err)
+       }
+
+       input, err := dnstap.NewFrameStreamSockInputFromPath(*unixSocket)
+       if err != nil {
+               panic(err)
+       }
+
+       output := make(chan []byte)
+       go input.ReadInto(output)
+
+       ctx, cancel := context.WithTimeout(context.Background(), testTimeout)
+
+       // Create a UDP listening socket on random port
+       // FD will be passed on to kresd
+       addr, file, err := listenOn()
+       if err != nil {
+               panic(err)
+       }
+       if *debug {
+               log.Printf("listen addr:%v", addr)
+       }
+       ctx = context.WithValue(ctx, "file", file)
+       ctx = context.WithValue(ctx, "debug", *debug)
+
+       ch, err := runKresd(ctx, *kresdPath, *configFile, kresdStartGracePeriod)
+       if err != nil {
+               panic(err)
+       }
+
+       log.Printf("Waiting for kresd to start\n")
+       status := <-ch
+       if !status {
+               os.Exit(1) // error starting
+       }
+
+       go func() {
+               parts := strings.Split(*qnames, ",")
+
+               if len(parts) == 0 {
+                       log.Printf("qname count is 0")
+               }
+               for _, name := range parts {
+                       m := new(dns.Msg)
+                       fqdn := dns.Fqdn(name)
+                       m.SetQuestion(fqdn, dns.TypeA)
+                       c := new(dns.Client)
+                       resp, _, err := c.Exchange(m, fmt.Sprintf("%v", addr))
+                       if err != nil {
+                               log.Printf("%v\n", err)
+                               os.Exit(1) // Test Failed
+                       }
+                       if *debug {
+                               log.Printf("Response: %v", resp)
+                       }
+
+                       // Check dnstap output
+                       o := <-output
+                       if *debug {
+                               log.Printf("raw dnstap:%v", o)
+                       }
+                       dtName, err := qnameFromFrame(o)
+                       if err != nil {
+                               log.Printf("%v\n", err)
+                               os.Exit(1)
+                       }
+                       if fqdn != dtName {
+                               log.Printf("expected %v got %v", fqdn, dtName)
+                               os.Exit(1) // Test failed
+                       }
+                       log.Printf("matched qname: %v", dtName)
+               }
+               cancel() // Send signal to close daemon
+       }()
+
+       status = <-ch
+       if !status {
+               os.Exit(1) // error in wait
+       }
+       log.Printf("Tested OK\n")
+}
diff --git a/tests/dnstap/src/dnstap-test/vendor/manifest b/tests/dnstap/src/dnstap-test/vendor/manifest
new file mode 100644 (file)
index 0000000..27c1dec
--- /dev/null
@@ -0,0 +1,55 @@
+{
+       "version": 0,
+       "dependencies": [
+               {
+                       "importpath": "github.com/cloudflare/dns",
+                       "repository": "https://github.com/cloudflare/dns",
+                       "vcs": "git",
+                       "revision": "e20ffa3da443071c7b3d164dec5b1f80dfb2ecf3",
+                       "branch": "master",
+                       "notests": true
+               },
+               {
+                       "importpath": "github.com/dnstap/golang-dnstap",
+                       "repository": "https://github.com/dnstap/golang-dnstap",
+                       "vcs": "git",
+                       "revision": "0145fd8482619f9c04788c7ba4e96cdeef64a041",
+                       "branch": "master",
+                       "notests": true
+               },
+               {
+                       "importpath": "github.com/farsightsec/golang-framestream",
+                       "repository": "https://github.com/farsightsec/golang-framestream",
+                       "vcs": "git",
+                       "revision": "b600ccf606747139c84b6d69b5c3988164db4d42",
+                       "branch": "master",
+                       "notests": true
+               },
+               {
+                       "importpath": "github.com/golang/protobuf/proto",
+                       "repository": "https://github.com/golang/protobuf",
+                       "vcs": "git",
+                       "revision": "8ee79997227bf9b34611aee7946ae64735e6fd93",
+                       "branch": "master",
+                       "path": "/proto",
+                       "notests": true
+               },
+               {
+                       "importpath": "github.com/golang/protobuf/ptypes/any",
+                       "repository": "https://github.com/golang/protobuf",
+                       "vcs": "git",
+                       "revision": "8ee79997227bf9b34611aee7946ae64735e6fd93",
+                       "branch": "master",
+                       "path": "ptypes/any",
+                       "notests": true
+               },
+               {
+                       "importpath": "github.com/miekg/dns",
+                       "repository": "https://github.com/miekg/dns",
+                       "vcs": "git",
+                       "revision": "f4d2b086946a624202dc59e6a43f72e8f3f02bc1",
+                       "branch": "master",
+                       "notests": true
+               }
+       ]
+}
\ No newline at end of file
index 95244401357c8e0f45ced27731598c01919e3a8f..fa0ed28a03670d6acb1f9d22b3e6411392b3d898 100644 (file)
@@ -5,6 +5,10 @@ else
 $(warning cmocka not found, skipping unit tests)
 endif
 
+ifeq ($(ENABLE_DNSTAP)&$(HAS_go),yes&yes)
+include tests/dnstap/src/dnstap-test/dnstap.mk
+endif
+
 # Integration tests with Deckard
 deckard_DIR := tests/deckard
 TESTS := sets/resolver
@@ -24,7 +28,7 @@ check-integration: $(deckard_DIR)/Makefile
 deckard: check-integration
 
 # Targets
-tests: check-unit
-tests-clean: $(foreach test,$(tests_BIN),$(test)-clean) mock_cmodule-clean
+tests: check-unit check-dnstap
+tests-clean: $(foreach test,$(tests_BIN),$(test)-clean) mock_cmodule-clean clean-dnstap
 
-.PHONY: tests tests-clean check-integration deckard
+.PHONY: tests tests-clean check-integration deckard check-dnstap clean-dnstap