Add Meta data to the resolver
This commit is contained in:
parent
fc0ffa20f7
commit
ec441e36e1
|
@ -15,7 +15,7 @@ func main() {
|
|||
m.Question = make([]dns.Question, 1)
|
||||
m.Question[0] = dns.Question{"atoom.net", dns.TypeAXFR, dns.ClassINET}
|
||||
|
||||
ch <- resolver.Msg{m, nil}
|
||||
ch <- resolver.Msg{m, nil, nil}
|
||||
for dm := range ch {
|
||||
fmt.Printf("%v\n",dm.Dns)
|
||||
}
|
||||
|
|
|
@ -28,13 +28,13 @@ func main() {
|
|||
// set the resolver to query the NS directly
|
||||
r.Servers = []string{a.String()}
|
||||
m.Question[0] = dns.Question{"version.bind.", dns.TypeTXT, dns.ClassCHAOS}
|
||||
qr <- resolver.Msg{m, nil}
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in = <-qr
|
||||
if in.Dns != nil && in.Dns.Answer != nil {
|
||||
fmt.Printf("%v\n", in.Dns.Answer[0])
|
||||
}
|
||||
m.Question[0] = dns.Question{"hostname.bind.", dns.TypeTXT, dns.ClassCHAOS}
|
||||
qr <- resolver.Msg{m, nil}
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in = <-qr
|
||||
if in.Dns != nil && in.Dns.Answer != nil {
|
||||
fmt.Printf("%v\n", in.Dns.Answer[0])
|
||||
|
@ -42,7 +42,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Stop the resolver, send it a null mesg
|
||||
qr <- resolver.Msg{nil, nil}
|
||||
qr <- resolver.Msg{nil, nil, nil}
|
||||
<-qr
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ func addresses(qr chan resolver.Msg, name string) []net.IP {
|
|||
var ips []net.IP
|
||||
|
||||
m.Question[0] = dns.Question{os.Args[1], dns.TypeA, dns.ClassINET}
|
||||
qr <- resolver.Msg{m, nil}
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in := <-qr
|
||||
|
||||
if in.Dns == nil {
|
||||
|
@ -69,7 +69,7 @@ func addresses(qr chan resolver.Msg, name string) []net.IP {
|
|||
ips = append(ips, a.(*dns.RR_A).A)
|
||||
}
|
||||
m.Question[0] = dns.Question{os.Args[1], dns.TypeAAAA, dns.ClassINET}
|
||||
qr <- resolver.Msg{m, nil}
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in = <-qr
|
||||
|
||||
if in.Dns == nil {
|
||||
|
|
|
@ -23,7 +23,7 @@ func main() {
|
|||
m.Question = make([]dns.Question, 1)
|
||||
m.Question[0] = dns.Question{os.Args[1], dns.TypeMX, dns.ClassINET}
|
||||
|
||||
qr <- resolver.Msg{m, nil}
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in := <-qr
|
||||
if in.Dns != nil {
|
||||
if in.Dns.Rcode != dns.RcodeSuccess {
|
||||
|
@ -39,6 +39,6 @@ func main() {
|
|||
}
|
||||
|
||||
// Stop the resolver, send it a null mesg
|
||||
qr <- resolver.Msg{nil, nil}
|
||||
qr <- resolver.Msg{nil, nil, nil}
|
||||
<-qr
|
||||
}
|
||||
|
|
|
@ -38,13 +38,7 @@ FLAGS:
|
|||
nameserver = flag.Arg(i)
|
||||
continue FLAGS
|
||||
}
|
||||
// If it looks like a class, it is a class
|
||||
for k, v := range dns.Class_str {
|
||||
if v == strings.ToUpper(flag.Arg(i)) {
|
||||
qclass = k
|
||||
continue FLAGS
|
||||
}
|
||||
}
|
||||
// First class, then type, to make ANY queries possible
|
||||
// And if it looks like type, it is a type
|
||||
for k, v := range dns.Rr_str {
|
||||
if v == strings.ToUpper(flag.Arg(i)) {
|
||||
|
@ -52,6 +46,13 @@ FLAGS:
|
|||
continue FLAGS
|
||||
}
|
||||
}
|
||||
// If it looks like a class, it is a class
|
||||
for k, v := range dns.Class_str {
|
||||
if v == strings.ToUpper(flag.Arg(i)) {
|
||||
qclass = k
|
||||
continue FLAGS
|
||||
}
|
||||
}
|
||||
// Anything else is a qname
|
||||
qname = append(qname, flag.Arg(i))
|
||||
}
|
||||
|
@ -96,17 +97,18 @@ FLAGS:
|
|||
for _, v := range qname {
|
||||
m.Question[0] = dns.Question{v, qtype, qclass}
|
||||
m.SetId()
|
||||
qr <- resolver.Msg{m, nil}
|
||||
qr <- resolver.Msg{m, nil, nil}
|
||||
in := <-qr
|
||||
if in.Dns != nil {
|
||||
if m.Id != in.Dns.Id {
|
||||
fmt.Printf("Id mismatch\n")
|
||||
}
|
||||
fmt.Printf("%v\n", in.Dns)
|
||||
fmt.Printf("%s\n", in.Meta)
|
||||
} else {
|
||||
fmt.Printf("%v\n", in.Error.String())
|
||||
}
|
||||
}
|
||||
qr <- resolver.Msg{nil, nil}
|
||||
qr <- resolver.Msg{nil, nil, nil}
|
||||
<-qr
|
||||
}
|
||||
|
|
18
dns.go
18
dns.go
|
@ -52,6 +52,24 @@ func (e *Error) String() string {
|
|||
return e.Error
|
||||
}
|
||||
|
||||
// Meta data when querying
|
||||
type Meta struct {
|
||||
QLen int // query length in bytes
|
||||
RLen int // reply length in bytes
|
||||
QueryStart int64 // start of query in nanoseconds epoch
|
||||
QueryEnd int64 // end of query in nanosecond epoch
|
||||
}
|
||||
|
||||
func (m *Meta) String() string {
|
||||
s := ";; Query time: " + strconv.Itoa(int(m.QueryEnd - m.QueryStart)) + " nsec"
|
||||
s += "\n;; MSG SIZE rcvd: " + strconv.Itoa(m.RLen) + ", sent: " + strconv.Itoa(m.QLen)
|
||||
rf := float32(m.RLen)
|
||||
qf := float32(m.QLen)
|
||||
s += " (" + strconv.Ftoa32(rf/qf, 'f', 2) + ":1)"
|
||||
// WHEN??
|
||||
return s
|
||||
}
|
||||
|
||||
type RR interface {
|
||||
Header() *RR_Header
|
||||
String() string
|
||||
|
|
1
msg.go
1
msg.go
|
@ -92,6 +92,7 @@ var Rr_str = map[uint16]string{
|
|||
TypeTSIG: "TSIG", // Meta RR
|
||||
TypeAXFR: "AXFR", // Meta RR
|
||||
TypeIXFR: "IXFR", // Meta RR
|
||||
TypeALL: "ANY", // Meta RR
|
||||
}
|
||||
|
||||
// Reverse of Rr_str (needed for parsing)
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"os"
|
||||
"net"
|
||||
"dns"
|
||||
"time"
|
||||
)
|
||||
|
||||
const packErr = "Failed to pack message"
|
||||
|
@ -39,6 +40,7 @@ const servErr = "No servers could be reached"
|
|||
// Sending a nil message instructs to resolver to stop.
|
||||
type Msg struct {
|
||||
Dns *dns.Msg
|
||||
Meta *dns.Meta
|
||||
Error os.Error
|
||||
}
|
||||
|
||||
|
@ -71,6 +73,7 @@ func query(res *Resolver, msg chan Msg) {
|
|||
err os.Error
|
||||
in *dns.Msg
|
||||
port string
|
||||
meta *dns.Meta
|
||||
)
|
||||
// len(res.Server) == 0 can be perfectly valid, when setting up the resolver
|
||||
if res.Port == "" {
|
||||
|
@ -84,7 +87,7 @@ func query(res *Resolver, msg chan Msg) {
|
|||
case out := <-msg: //msg received
|
||||
if out.Dns == nil {
|
||||
// nil message, quit the goroutine
|
||||
msg <- Msg{nil, nil}
|
||||
msg <- Msg{nil, nil, nil}
|
||||
close(msg)
|
||||
return
|
||||
}
|
||||
|
@ -97,7 +100,7 @@ func query(res *Resolver, msg chan Msg) {
|
|||
}
|
||||
sending, ok := out.Dns.Pack()
|
||||
if !ok {
|
||||
msg <- Msg{nil, &dns.Error{Error: packErr}}
|
||||
msg <- Msg{nil, nil, &dns.Error{Error: packErr}}
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -113,9 +116,9 @@ func query(res *Resolver, msg chan Msg) {
|
|||
continue
|
||||
}
|
||||
if res.Tcp {
|
||||
in, err = exchangeTCP(c, sending, res, true)
|
||||
in, meta, err = exchangeTCP(c, sending, res, true)
|
||||
} else {
|
||||
in, err = exchangeUDP(c, sending, res, true)
|
||||
in, meta, err = exchangeUDP(c, sending, res, true)
|
||||
}
|
||||
|
||||
// Check id in.id != out.id, should be checked in the client!
|
||||
|
@ -123,11 +126,13 @@ func query(res *Resolver, msg chan Msg) {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
meta.QLen = len(sending)
|
||||
if err != nil {
|
||||
msg <- Msg{nil, err}
|
||||
msg <- Msg{nil, meta, err}
|
||||
} else {
|
||||
msg <- Msg{in, nil}
|
||||
msg <- Msg{in, meta, nil}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,6 +151,7 @@ func (res *Resolver) NewXfer() (ch chan Msg) {
|
|||
func axfr(res *Resolver, msg chan Msg) {
|
||||
var port string
|
||||
var err os.Error
|
||||
meta := new(dns.Meta)
|
||||
var in *dns.Msg
|
||||
if res.Port == "" {
|
||||
port = "53"
|
||||
|
@ -158,7 +164,7 @@ func axfr(res *Resolver, msg chan Msg) {
|
|||
case out := <-msg: // msg received
|
||||
if out.Dns == nil {
|
||||
// stop
|
||||
msg <- Msg{nil, nil}
|
||||
msg <- Msg{nil, nil, nil}
|
||||
close(msg)
|
||||
return
|
||||
}
|
||||
|
@ -166,8 +172,9 @@ func axfr(res *Resolver, msg chan Msg) {
|
|||
out.Dns.SetId()
|
||||
sending, ok := out.Dns.Pack()
|
||||
if !ok {
|
||||
msg <- Msg{nil, &dns.Error{Error: packErr}}
|
||||
msg <- Msg{nil, nil, &dns.Error{Error: packErr}}
|
||||
}
|
||||
meta.QLen = len(sending)
|
||||
SERVER:
|
||||
for i := 0; i < len(res.Servers); i++ {
|
||||
server := res.Servers[i] + ":" + port
|
||||
|
@ -180,9 +187,9 @@ func axfr(res *Resolver, msg chan Msg) {
|
|||
// Start the AXFR
|
||||
for {
|
||||
if first {
|
||||
in, cerr = exchangeTCP(c, sending, res, true)
|
||||
in, meta, cerr = exchangeTCP(c, sending, res, true)
|
||||
} else {
|
||||
in, cerr = exchangeTCP(c, sending, res, false)
|
||||
in, meta, cerr = exchangeTCP(c, sending, res, false)
|
||||
}
|
||||
|
||||
if cerr != nil {
|
||||
|
@ -204,12 +211,12 @@ func axfr(res *Resolver, msg chan Msg) {
|
|||
if !first {
|
||||
if !checkSOA(in, false) {
|
||||
// Soa record not the last one
|
||||
msg <- Msg{in, nil}
|
||||
msg <- Msg{in, meta, nil}
|
||||
continue
|
||||
// next
|
||||
} else {
|
||||
c.Close()
|
||||
msg <- Msg{in, nil}
|
||||
msg <- Msg{in, meta, nil}
|
||||
close(msg)
|
||||
return
|
||||
}
|
||||
|
@ -218,7 +225,7 @@ func axfr(res *Resolver, msg chan Msg) {
|
|||
println("Should never be reached")
|
||||
return
|
||||
}
|
||||
msg <- Msg{nil, err}
|
||||
msg <- Msg{nil, meta, err}
|
||||
close(msg)
|
||||
return
|
||||
}
|
||||
|
@ -228,9 +235,10 @@ func axfr(res *Resolver, msg chan Msg) {
|
|||
|
||||
// Send a request on the connection and hope for a reply.
|
||||
// Up to res.Attempts attempts.
|
||||
func exchangeUDP(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Error) {
|
||||
func exchangeUDP(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, *dns.Meta, os.Error) {
|
||||
var timeout int64
|
||||
var attempts int
|
||||
meta := new(dns.Meta)
|
||||
if r.Mangle != nil {
|
||||
m = r.Mangle(m)
|
||||
}
|
||||
|
@ -246,37 +254,41 @@ func exchangeUDP(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Err
|
|||
}
|
||||
for a := 0; a < attempts; a++ {
|
||||
if send {
|
||||
meta.QueryStart = time.Nanoseconds()
|
||||
err := sendUDP(m, c)
|
||||
if err != nil {
|
||||
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return nil, meta, err
|
||||
}
|
||||
}
|
||||
|
||||
c.SetReadTimeout(timeout * 1e9) // nanoseconds
|
||||
buf, err := recvUDP(c)
|
||||
meta.QueryEnd = time.Nanoseconds()
|
||||
if err != nil {
|
||||
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return nil, meta, err
|
||||
}
|
||||
|
||||
in := new(dns.Msg)
|
||||
meta.RLen = len(buf)
|
||||
if !in.Unpack(buf) {
|
||||
continue
|
||||
}
|
||||
return in, nil
|
||||
return in, meta, nil
|
||||
}
|
||||
return nil, &dns.Error{Error: servErr}
|
||||
return nil, meta, &dns.Error{Error: servErr}
|
||||
}
|
||||
|
||||
// Up to res.Attempts attempts.
|
||||
func exchangeTCP(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Error) {
|
||||
func exchangeTCP(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, *dns.Meta, os.Error) {
|
||||
var timeout int64
|
||||
var attempts int
|
||||
meta := new(dns.Meta)
|
||||
if r.Mangle != nil {
|
||||
m = r.Mangle(m)
|
||||
}
|
||||
|
@ -294,31 +306,34 @@ func exchangeTCP(c net.Conn, m []byte, r *Resolver, send bool) (*dns.Msg, os.Err
|
|||
for a := 0; a < attempts; a++ {
|
||||
// only send something when told so
|
||||
if send {
|
||||
meta.QueryStart = time.Nanoseconds()
|
||||
err := sendTCP(m,c)
|
||||
if err != nil {
|
||||
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return nil, meta, err
|
||||
}
|
||||
}
|
||||
|
||||
c.SetReadTimeout(timeout * 1e9) // nanoseconds
|
||||
// The server replies with two bytes length
|
||||
buf, err := recvTCP(c)
|
||||
meta.QueryEnd = time.Nanoseconds()
|
||||
if err != nil {
|
||||
if e, ok := err.(net.Error); ok && e.Timeout() {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return nil, meta, err
|
||||
}
|
||||
in := new(dns.Msg)
|
||||
meta.RLen = len(buf)
|
||||
if !in.Unpack(buf) {
|
||||
continue
|
||||
}
|
||||
return in, nil
|
||||
return in, meta, nil
|
||||
}
|
||||
return nil, &dns.Error{Error: servErr}
|
||||
return nil, meta, &dns.Error{Error: servErr}
|
||||
}
|
||||
|
||||
func sendUDP(m []byte,c net.Conn) os.Error {
|
||||
|
|
|
@ -17,7 +17,7 @@ func TestResolver(t *testing.T) {
|
|||
|
||||
// ask something
|
||||
m.Question[0] = dns.Question{"miek.nl", dns.TypeSOA, dns.ClassINET}
|
||||
ch <- Msg{m, nil}
|
||||
ch <- Msg{m, nil, nil}
|
||||
in := <-ch
|
||||
|
||||
if in.Dns != nil && in.Dns.Rcode != dns.RcodeSuccess {
|
||||
|
@ -28,7 +28,7 @@ func TestResolver(t *testing.T) {
|
|||
|
||||
// ask something
|
||||
m.Question[0] = dns.Question{"www.nlnetlabs.nl", dns.TypeRRSIG, dns.ClassINET}
|
||||
ch <- Msg{m, nil}
|
||||
ch <- Msg{m, nil, nil}
|
||||
in = <-ch
|
||||
|
||||
if in.Dns != nil && in.Dns.Rcode != dns.RcodeSuccess {
|
||||
|
@ -37,7 +37,7 @@ func TestResolver(t *testing.T) {
|
|||
t.Logf("%v\n", in)
|
||||
}
|
||||
|
||||
ch <- Msg{nil, nil}
|
||||
ch <- Msg{nil, nil, nil}
|
||||
<-ch
|
||||
}
|
||||
|
||||
|
@ -62,14 +62,14 @@ func TestResolverEdns(t *testing.T) {
|
|||
edns.SetUDPSize(2048)
|
||||
edns.SetDo()
|
||||
edns.Option = make([]dns.Option, 1)
|
||||
edns.SetNsidToHex("") // Empty to request it
|
||||
edns.SetNsid("") // Empty to request it
|
||||
|
||||
// ask something
|
||||
m.Question[0] = dns.Question{"powerdns.nl", dns.TypeDNSKEY, dns.ClassINET}
|
||||
m.Extra = make([]dns.RR, 1)
|
||||
m.Extra[0] = edns
|
||||
|
||||
ch <- Msg{m, nil}
|
||||
ch <- Msg{m, nil, nil}
|
||||
in := <-ch
|
||||
if in.Dns != nil {
|
||||
if in.Dns.Rcode != dns.RcodeSuccess {
|
||||
|
@ -78,7 +78,7 @@ func TestResolverEdns(t *testing.T) {
|
|||
t.Fail()
|
||||
}
|
||||
}
|
||||
ch <- Msg{nil, nil}
|
||||
ch <- Msg{nil, nil, nil}
|
||||
<-ch // wait for ch to close channel
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ func TestResolverTsig(t *testing.T) {
|
|||
// Add it to the msg
|
||||
m.Extra[0] = tsig
|
||||
|
||||
ch <- Msg{m, nil}
|
||||
ch <- Msg{m, nil, nil}
|
||||
in := <-ch
|
||||
if in.Dns != nil {
|
||||
if in.Dns.Rcode != dns.RcodeSuccess {
|
||||
|
@ -117,7 +117,7 @@ func TestResolverTsig(t *testing.T) {
|
|||
t.Fail()
|
||||
}
|
||||
}
|
||||
ch <- Msg{nil, nil}
|
||||
ch <- Msg{nil, nil, nil}
|
||||
<-ch // wait for ch to close channel
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ func TestAXFR(t *testing.T) {
|
|||
m.Question[0] = dns.Question{"miek.nl", dns.TypeAXFR, dns.ClassINET}
|
||||
//m.Question[0] = dns.Question{"atoom.net", dns.TypeAXFR, dns.ClassINET}
|
||||
|
||||
ch <- Msg{m, nil}
|
||||
ch <- Msg{m, nil, nil}
|
||||
for dm := range ch {
|
||||
var _ = dm
|
||||
/* fmt.Printf("%v\n",dm.Dns) */
|
||||
|
@ -147,7 +147,7 @@ func TestFromFile(t *testing.T) {
|
|||
m.Question = make([]dns.Question, 1)
|
||||
m.Question[0] = dns.Question{"a.miek.nl", dns.TypeA, dns.ClassINET}
|
||||
|
||||
ch <- Msg{m, nil}
|
||||
ch <- Msg{m, nil, nil}
|
||||
in := <-ch
|
||||
if in.Dns != nil {
|
||||
if in.Dns.Rcode != dns.RcodeSuccess {
|
||||
|
|
|
@ -41,6 +41,7 @@ type msg struct {
|
|||
addr net.Addr // remote address
|
||||
msg []byte // raw dns message
|
||||
err os.Error // any errors
|
||||
// Meta stuff
|
||||
}
|
||||
|
||||
// Every nameserver implements the Responder interface. It defines
|
||||
|
|
Loading…
Reference in New Issue