Add debug.Hexdump (#1902)
Allow plugins to dump messages in text pcap to the log. The forward plugin does this when a reply does not much the query. If the debug plugin isn't loaded Hexdump and Hexdumpf are noop. Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
parent
063e673bc4
commit
e6f81ebb31
5 changed files with 169 additions and 3 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,8 +4,6 @@ Corefile
|
||||||
coredns
|
coredns
|
||||||
coredns.exe
|
coredns.exe
|
||||||
coredns.exe~
|
coredns.exe~
|
||||||
debug
|
|
||||||
debug.test
|
|
||||||
kubectl
|
kubectl
|
||||||
go-test-tmpfile*
|
go-test-tmpfile*
|
||||||
coverage.txt
|
coverage.txt
|
||||||
|
|
|
@ -10,7 +10,7 @@ Normally CoreDNS will recover from panics, using *debug* inhibits this. The main
|
||||||
to help testing. A side effect of using *debug* is that `log.Debug` and `log.Debugf` will be printed
|
to help testing. A side effect of using *debug* is that `log.Debug` and `log.Debugf` will be printed
|
||||||
to standard output.
|
to standard output.
|
||||||
|
|
||||||
Note that the *errors* plugin (if loaded) will also set a `recover` negating this setting.
|
Note that the *errors* plugin (if loaded) will also set a `recover` negating this setting.
|
||||||
|
|
||||||
## Syntax
|
## Syntax
|
||||||
|
|
||||||
|
@ -18,6 +18,21 @@ Note that the *errors* plugin (if loaded) will also set a `recover` negating thi
|
||||||
debug
|
debug
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
Some plugin will debug log DNS messages. This is done in the following format:
|
||||||
|
|
||||||
|
~~~
|
||||||
|
debug: 000000 00 0a 01 00 00 01 00 00 00 00 00 01 07 65 78 61
|
||||||
|
debug: 000010 6d 70 6c 65 05 6c 6f 63 61 6c 00 00 01 00 01 00
|
||||||
|
debug: 000020 00 29 10 00 00 00 80 00 00 00
|
||||||
|
debug: 00002a
|
||||||
|
~~~
|
||||||
|
|
||||||
|
Using `text2pcap` (part of Wireshark) this can be converted back to binary, with the following
|
||||||
|
command line: `text2pcap -i 17 -u 53,53`. Where 17 is the protocol (UDP) and 53 are the ports. These
|
||||||
|
ports allow wireshark to detect these packets as DNS messages.
|
||||||
|
|
||||||
|
Each plugin can decide to dump messages to aid in debugging.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
Disable the ability to recover from crashes and show debug logging:
|
Disable the ability to recover from crashes and show debug logging:
|
||||||
|
@ -27,3 +42,7 @@ Disable the ability to recover from crashes and show debug logging:
|
||||||
debug
|
debug
|
||||||
}
|
}
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
## Also See
|
||||||
|
|
||||||
|
https://www.wireshark.org/docs/man-pages/text2pcap.html.
|
||||||
|
|
72
plugin/debug/pcap.go
Normal file
72
plugin/debug/pcap.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/log"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hexdump converts the dns message m to a hex dump Whireshark can import.
|
||||||
|
// See https://www.wireshark.org/docs/man-pages/text2pcap.html.
|
||||||
|
// This output looks like this:
|
||||||
|
//
|
||||||
|
// 00000 dc bd 01 00 00 01 00 00 00 00 00 01 07 65 78 61
|
||||||
|
// 000010 6d 70 6c 65 05 6c 6f 63 61 6c 00 00 01 00 01 00
|
||||||
|
// 000020 00 29 10 00 00 00 80 00 00 00
|
||||||
|
// 00002a
|
||||||
|
//
|
||||||
|
// Hexdump will use log.Debug to write the dump to the log, each line
|
||||||
|
// is prefixed with 'debug: ' so the data can be easily extracted.
|
||||||
|
//
|
||||||
|
// msg will prefix the pcap dump.
|
||||||
|
func Hexdump(m *dns.Msg, v ...interface{}) {
|
||||||
|
if !log.D {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, _ := m.Pack()
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := "\n" + string(hexdump(buf))
|
||||||
|
v = append(v, out)
|
||||||
|
log.Debug(v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hexdumpf dumps a DNS message as Hexdump, but allows a format string.
|
||||||
|
func Hexdumpf(m *dns.Msg, format string, v ...interface{}) {
|
||||||
|
if !log.D {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, _ := m.Pack()
|
||||||
|
if len(buf) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
format += "\n%s"
|
||||||
|
v = append(v, hexdump(buf))
|
||||||
|
log.Debugf(format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexdump(data []byte) []byte {
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
|
||||||
|
newline := ""
|
||||||
|
for i := 0; i < len(data); i++ {
|
||||||
|
if i%16 == 0 {
|
||||||
|
fmt.Fprintf(b, "%s%s%06x", newline, prefix, i)
|
||||||
|
newline = "\n"
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, " %02x", data[i])
|
||||||
|
}
|
||||||
|
fmt.Fprintf(b, "\n%s%06x", prefix, len(data))
|
||||||
|
|
||||||
|
return b.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
const prefix = "debug: "
|
74
plugin/debug/pcap_test.go
Normal file
74
plugin/debug/pcap_test.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
golog "log"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coredns/coredns/plugin/pkg/log"
|
||||||
|
|
||||||
|
"github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func msg() *dns.Msg {
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetQuestion("example.local.", dns.TypeA)
|
||||||
|
m.SetEdns0(4096, true)
|
||||||
|
m.Id = 10
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleLogHexdump() {
|
||||||
|
buf, _ := msg().Pack()
|
||||||
|
h := hexdump(buf)
|
||||||
|
fmt.Println(string(h))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// debug: 000000 00 0a 01 00 00 01 00 00 00 00 00 01 07 65 78 61
|
||||||
|
// debug: 000010 6d 70 6c 65 05 6c 6f 63 61 6c 00 00 01 00 01 00
|
||||||
|
// debug: 000020 00 29 10 00 00 00 80 00 00 00
|
||||||
|
// debug: 00002a
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHexdump(t *testing.T) {
|
||||||
|
var f bytes.Buffer
|
||||||
|
golog.SetOutput(&f)
|
||||||
|
log.D = true
|
||||||
|
|
||||||
|
str := "Hi There!"
|
||||||
|
Hexdump(msg(), str)
|
||||||
|
logged := f.String()
|
||||||
|
|
||||||
|
if !strings.Contains(logged, "[DEBUG] "+str) {
|
||||||
|
t.Errorf("The string %s, is not contained in the logged output: %s", str, logged)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHexdumpf(t *testing.T) {
|
||||||
|
var f bytes.Buffer
|
||||||
|
golog.SetOutput(&f)
|
||||||
|
log.D = true
|
||||||
|
|
||||||
|
str := "Hi There!"
|
||||||
|
Hexdumpf(msg(), "%s %d", str, 10)
|
||||||
|
logged := f.String()
|
||||||
|
|
||||||
|
if !strings.Contains(logged, "[DEBUG] "+fmt.Sprintf("%s %d", str, 10)) {
|
||||||
|
t.Errorf("The string %s %d, is not contained in the logged output: %s", str, 10, logged)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoDebug(t *testing.T) {
|
||||||
|
var f bytes.Buffer
|
||||||
|
golog.SetOutput(&f)
|
||||||
|
log.D = false
|
||||||
|
|
||||||
|
str := "Hi There!"
|
||||||
|
Hexdumpf(msg(), "%s %d", str, 10)
|
||||||
|
if len(f.Bytes()) != 0 {
|
||||||
|
t.Errorf("Expected no output, got %d bytes", len(f.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/coredns/coredns/plugin"
|
"github.com/coredns/coredns/plugin"
|
||||||
|
"github.com/coredns/coredns/plugin/debug"
|
||||||
"github.com/coredns/coredns/request"
|
"github.com/coredns/coredns/request"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
@ -131,6 +132,8 @@ func (f *Forward) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
|
||||||
|
|
||||||
// Check if the reply is correct; if not return FormErr.
|
// Check if the reply is correct; if not return FormErr.
|
||||||
if !state.Match(ret) {
|
if !state.Match(ret) {
|
||||||
|
debug.Hexdumpf(ret, "Wrong reply for id: %d, %s/%d", state.QName(), state.QType())
|
||||||
|
|
||||||
formerr := state.ErrorMessage(dns.RcodeFormatError)
|
formerr := state.ErrorMessage(dns.RcodeFormatError)
|
||||||
w.WriteMsg(formerr)
|
w.WriteMsg(formerr)
|
||||||
return 0, nil
|
return 0, nil
|
||||||
|
|
Loading…
Add table
Reference in a new issue