seeing some light in the query API
global channels look to be helpfull
This commit is contained in:
parent
518ba6f506
commit
0449ff62a2
2
TODO
2
TODO
|
@ -16,8 +16,10 @@ Todo:
|
||||||
* encoding NSEC3/NSEC bitmaps, DEcoding works
|
* encoding NSEC3/NSEC bitmaps, DEcoding works
|
||||||
* HIP RR (needs list of domain names, need slice stuff for that)
|
* HIP RR (needs list of domain names, need slice stuff for that)
|
||||||
* Is subdomain, is glue helper functions for this kind of stuff
|
* Is subdomain, is glue helper functions for this kind of stuff
|
||||||
|
* Make QuerySimple even simpler??
|
||||||
|
|
||||||
Issues:
|
Issues:
|
||||||
|
* FunkenSturm is kaput.
|
||||||
* Check the network order, it works now, but this is on Intel??
|
* Check the network order, it works now, but this is on Intel??
|
||||||
* Make the testsuite work with public DNS servers
|
* Make the testsuite work with public DNS servers
|
||||||
* pack/Unpack smaller. EDNS 'n stuff can be folded in
|
* pack/Unpack smaller. EDNS 'n stuff can be folded in
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func main() {
|
func main() {
|
||||||
var dnssec *bool = flag.Bool("dnssec", false, "Request DNSSEC records")
|
var dnssec *bool = flag.Bool("dnssec", false, "Request DNSSEC records")
|
||||||
var short *bool = flag.Bool("short", false, "Abbriate long DNSKEY and RRSIG RRs")
|
var short *bool = flag.Bool("short", false, "Abbriate long DNSKEY and RRSIG RRs")
|
||||||
var port *string = flag.String("port", "53", "Set the query port")
|
//var port *string = flag.String("port", "53", "Set the query port")
|
||||||
var aa *bool = flag.Bool("aa", false, "Set AA flag in query")
|
var aa *bool = flag.Bool("aa", false, "Set AA flag in query")
|
||||||
var ad *bool = flag.Bool("ad", false, "Set AD flag in query")
|
var ad *bool = flag.Bool("ad", false, "Set AD flag in query")
|
||||||
var cd *bool = flag.Bool("cd", false, "Set CD flag in query")
|
var cd *bool = flag.Bool("cd", false, "Set CD flag in query")
|
||||||
|
@ -24,8 +24,8 @@ func main() {
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to think about it... Config
|
// Need to think about it... Config
|
||||||
c, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
c, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||||
nameserver := "@" + c.Servers[0]
|
nameserver := "@" + c.Servers[0]
|
||||||
qtype := uint16(dns.TypeA) // Default qtype
|
qtype := uint16(dns.TypeA) // Default qtype
|
||||||
qclass := uint16(dns.ClassINET) // Default qclass
|
qclass := uint16(dns.ClassINET) // Default qclass
|
||||||
|
@ -70,9 +70,11 @@ Flags:
|
||||||
|
|
||||||
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
||||||
|
|
||||||
d := new(dns.Conn)
|
// Port stuff does not work
|
||||||
d.RemoteAddr = nameserver + ":" + *port
|
d := new(dns.Conn)
|
||||||
d.Attempts = 1
|
// d.RemoteAddr = nameserver + ":" + *port
|
||||||
|
d.RemoteAddr = nameserver // works with /etc/resolv.conf
|
||||||
|
d.Attempts = 1
|
||||||
|
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.MsgHdr.Authoritative = *aa
|
m.MsgHdr.Authoritative = *aa
|
||||||
|
@ -92,35 +94,65 @@ Flags:
|
||||||
m.Extra[0] = opt
|
m.Extra[0] = opt
|
||||||
}
|
}
|
||||||
|
|
||||||
in := make(chan dns.Query)
|
err := make(chan os.Error)
|
||||||
var out chan dns.Query
|
if *tcp {
|
||||||
if *tcp {
|
go query(err, "tcp")
|
||||||
out = dns.QueryAndServeTCP(in, nil)
|
} else {
|
||||||
} else {
|
go query(err, "udp")
|
||||||
out = dns.QueryAndServeUDP(in, nil)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range qname {
|
dns.QueryReply = make(chan dns.Query)
|
||||||
m.Question[0] = dns.Question{v, qtype, qclass}
|
dns.QueryRequest = make(chan dns.Query)
|
||||||
m.Id = dns.Id()
|
// Start the quering in a closure
|
||||||
in <- dns.Query{Msg: m, Conn: d}
|
go func() {
|
||||||
|
for _, v := range qname {
|
||||||
|
m.Question[0] = dns.Question{v, qtype, qclass}
|
||||||
|
m.Id = dns.Id()
|
||||||
|
dns.QueryRequest <- dns.Query{Msg: m, Conn: d}
|
||||||
|
println("querying")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
r := <-out
|
i :=0
|
||||||
|
for {
|
||||||
if r.Msg != nil {
|
select {
|
||||||
if r.Msg.Id != m.Id {
|
case r := <-dns.QueryReply:
|
||||||
fmt.Printf("Id mismatch\n")
|
if r.Msg != nil {
|
||||||
|
if r.Msg.Id != m.Id {
|
||||||
|
fmt.Printf("Id mismatch\n")
|
||||||
|
}
|
||||||
|
if *short {
|
||||||
|
r.Msg = shortMsg(r.Msg)
|
||||||
|
}
|
||||||
|
fmt.Printf("%v", r.Msg)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%v\n", r.Err.String())
|
||||||
}
|
}
|
||||||
if *short {
|
default:
|
||||||
r.Msg = shortMsg(r.Msg)
|
|
||||||
}
|
|
||||||
fmt.Printf("%v", r.Msg)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("%v\n", r.Err.String())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func query(e chan os.Error, tcp string) {
|
||||||
|
switch tcp {
|
||||||
|
case "tcp":
|
||||||
|
err := dns.QueryAndServeTCP(qhandle)
|
||||||
|
e <- err
|
||||||
|
case "udp":
|
||||||
|
err := dns.QueryAndServeUDP(qhandle)
|
||||||
|
e <- err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// reply checking 'n stuff
|
||||||
|
func qhandle(d *dns.Conn, i *dns.Msg) {
|
||||||
|
o, err := d.ExchangeMsg(i, false)
|
||||||
|
dns.QueryReply <- dns.Query{Msg: o, Conn: d, Err: err}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Walk trough message and short Key data and Sig data
|
// Walk trough message and short Key data and Sig data
|
||||||
func shortMsg(in *dns.Msg) *dns.Msg {
|
func shortMsg(in *dns.Msg) *dns.Msg {
|
||||||
for i := 0; i < len(in.Answer); i++ {
|
for i := 0; i < len(in.Answer); i++ {
|
||||||
|
|
|
@ -5,41 +5,66 @@ package main
|
||||||
// zone contents.
|
// zone contents.
|
||||||
// This zone is then checked cryptographically is
|
// This zone is then checked cryptographically is
|
||||||
// everything is correct.
|
// everything is correct.
|
||||||
|
// When the message is deemed correct a remote
|
||||||
|
// server is sent a notify to retrieve the ixfr/axfr.
|
||||||
// If a new DNSKEY record is seen for the apex and
|
// If a new DNSKEY record is seen for the apex and
|
||||||
// it validates it writes this record to disk and
|
// it validates it writes this record to disk and
|
||||||
// this new key will be used in future validations.
|
// this new key will be used in future validations.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"fmt"
|
"fmt"
|
||||||
"dns"
|
"dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Static amount of RRs...
|
// Static amount of RRs...
|
||||||
type zone struct {
|
type zone struct {
|
||||||
name string
|
name string
|
||||||
rrs [10000]dns.RR
|
rrs [10000]dns.RR
|
||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
var Zone zone
|
var Zone zone
|
||||||
|
|
||||||
func handle(d *dns.Conn, i *dns.Msg) {
|
func handle(d *dns.Conn, i *dns.Msg) {
|
||||||
if i.MsgHdr.Response == true {
|
/* send response here, how ??? */
|
||||||
return
|
if i.MsgHdr.Response == true {
|
||||||
}
|
return
|
||||||
handleNotify(d, i)
|
}
|
||||||
handleXfr(d, i)
|
handleNotify(d, i)
|
||||||
|
handleXfr(d, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func qhandle(d *dns.Conn, i *dns.Msg) {
|
||||||
|
// We should send i to d.RemoteAddr
|
||||||
|
// simpleQuery here
|
||||||
|
|
||||||
|
// what do we do with the reply
|
||||||
|
///handle HERE!!?? Need globals or stuff in d...
|
||||||
|
|
||||||
|
// in/out channel must be accessible
|
||||||
}
|
}
|
||||||
|
|
||||||
func listen(addr string, e chan os.Error, tcp string) {
|
func listen(addr string, e chan os.Error, tcp string) {
|
||||||
|
switch tcp {
|
||||||
|
case "tcp":
|
||||||
|
err := dns.ListenAndServeTCP(addr, handle)
|
||||||
|
e <- err
|
||||||
|
case "udp":
|
||||||
|
err := dns.ListenAndServeUDP(addr, handle)
|
||||||
|
e <- err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func query(e chan os.Error, tcp string) {
|
||||||
switch tcp {
|
switch tcp {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
err := dns.ListenAndServeTCP(addr, handle)
|
err := dns.QueryAndServeTCP(qhandle)
|
||||||
e <- err
|
e <- err
|
||||||
case "udp":
|
case "udp":
|
||||||
err := dns.ListenAndServeUDP(addr, handle)
|
err := dns.QueryAndServeUDP(qhandle)
|
||||||
e <- err
|
e <- err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -47,6 +72,12 @@ func listen(addr string, e chan os.Error, tcp string) {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
err := make(chan os.Error)
|
err := make(chan os.Error)
|
||||||
|
|
||||||
|
// Outgoing queries
|
||||||
|
go query(err, "tcp")
|
||||||
|
go query(err, "udp")
|
||||||
|
|
||||||
|
// Incoming queries
|
||||||
go listen("127.0.0.1:8053", err, "tcp")
|
go listen("127.0.0.1:8053", err, "tcp")
|
||||||
go listen("[::1]:8053", err, "tcp")
|
go listen("[::1]:8053", err, "tcp")
|
||||||
go listen("127.0.0.1:8053", err, "udp")
|
go listen("127.0.0.1:8053", err, "udp")
|
||||||
|
@ -61,6 +92,9 @@ forever:
|
||||||
case <-signal.Incoming:
|
case <-signal.Incoming:
|
||||||
fmt.Printf("Signal received, stopping")
|
fmt.Printf("Signal received, stopping")
|
||||||
break forever
|
break forever
|
||||||
|
case q := <-dns.QueryReply:
|
||||||
|
var _ = q
|
||||||
|
/* ... */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(err)
|
close(err)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
// Everything is assumed in the ClassINET class
|
// Everything is assumed in the ClassINET class. If
|
||||||
|
// you need other classes you are on your own.
|
||||||
|
|
||||||
// Create a reply packet from a request message.
|
// Create a reply packet from a request message.
|
||||||
func (dns *Msg) SetReply(request *Msg) {
|
func (dns *Msg) SetReply(request *Msg) {
|
||||||
|
|
21
dns.go
21
dns.go
|
@ -48,7 +48,7 @@
|
||||||
// Server side programming is also supported also by using a Conn structure.
|
// Server side programming is also supported also by using a Conn structure.
|
||||||
// Basic use pattern for creating an UDP DNS server:
|
// Basic use pattern for creating an UDP DNS server:
|
||||||
//
|
//
|
||||||
// func handle(d *Conn, m *Msg) { /* handle request */ }
|
// func handle(*Conn, *Msg, ...interface{}) { /* handle request */ }
|
||||||
//
|
//
|
||||||
// func listen(addr string, e chan os.Error) {
|
// func listen(addr string, e chan os.Error) {
|
||||||
// err := ListenAndServeUDP(addr, handle)
|
// err := ListenAndServeUDP(addr, handle)
|
||||||
|
@ -433,6 +433,25 @@ func (d *Conn) Exchange(request []byte, nosend bool) (reply []byte, err os.Error
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExchangeMsg combines a WriteMSg and a ReadMsg.
|
||||||
|
// First the request is written to d and then it waits
|
||||||
|
// for a reply with ReadMsg.
|
||||||
|
// If nosend is true, the write is skipped.
|
||||||
|
func (d *Conn) ExchangeMsg(request *Msg, nosend bool) (reply *Msg, err os.Error) {
|
||||||
|
if !nosend {
|
||||||
|
err = d.WriteMsg(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply = new(Msg)
|
||||||
|
err = d.ReadMsg(reply)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return reply, nil
|
||||||
|
}
|
||||||
|
|
||||||
type RR interface {
|
type RR interface {
|
||||||
Header() *RR_Header
|
Header() *RR_Header
|
||||||
String() string
|
String() string
|
||||||
|
|
166
resolver.go
166
resolver.go
|
@ -10,132 +10,92 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Request a query by sending to this channel.
|
||||||
|
var QueryRequest chan Query // *Query
|
||||||
|
// Listen for replies on this channel.
|
||||||
|
var QueryReply chan Query
|
||||||
|
|
||||||
// Query is used to communicate with the Query* functions.
|
// Query is used to communicate with the Query* functions.
|
||||||
type Query struct {
|
type Query struct {
|
||||||
// The query message.
|
// The query message.
|
||||||
Msg *Msg
|
Msg *Msg
|
||||||
// A Conn. Its only required to fill out Conn.RemoteAddr.
|
// A Conn. Its only required to fill out Conn.RemoteAddr.
|
||||||
// Optionally you may set Conn.Tsig if TSIG is required.
|
// Optionally you may set Conn.Tsig if TSIG is required.
|
||||||
// The rest of the structure is filled by the Query functions.
|
// The rest of the structure is filled by the Query functions.
|
||||||
Conn *Conn
|
Conn *Conn
|
||||||
// Any error when querying is returned in Err. The caller
|
//
|
||||||
// should just set this to nil.
|
Err os.Error
|
||||||
Err os.Error
|
|
||||||
// Query time in here?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryUDP handles one query. It reads an incoming request from
|
// QueryAndServeTCP listens for incoming requests on channel in and
|
||||||
// the in channel. The function f is executed in a seperate
|
// then calls f.
|
||||||
// goroutine and performs the actual UDP query.
|
// The function f is executed in a seperate goroutine and performs the actual
|
||||||
func QueryUDP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
// TCP query.
|
||||||
query("udp", in, out, f)
|
func QueryAndServeTCP(f func(*Conn, *Msg)) os.Error {
|
||||||
|
if f == nil {
|
||||||
|
return ErrHandle
|
||||||
|
}
|
||||||
|
if QueryReply == nil {
|
||||||
|
QueryReply = make(chan Query)
|
||||||
|
}
|
||||||
|
if QueryRequest == nil {
|
||||||
|
QueryRequest = make(chan Query)
|
||||||
|
}
|
||||||
|
query("tcp", f)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryTCP handles one query. It reads an incoming request from
|
// QueryAndServeUDP listens for incoming requests on channel in and
|
||||||
// the in channel. The function f is executed in a seperate
|
// then calls f.
|
||||||
// goroutine and performas the actual TCP query.
|
// The function f is executed in a seperate goroutine and performs the actual
|
||||||
func QueryTCP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
// UDP query.
|
||||||
query("tcp", in, out, f)
|
func QueryAndServeUDP(f func(*Conn, *Msg)) os.Error {
|
||||||
|
if f == nil {
|
||||||
|
return ErrHandle
|
||||||
|
}
|
||||||
|
if QueryReply == nil {
|
||||||
|
QueryReply = make(chan Query)
|
||||||
|
println("Creating channel reply")
|
||||||
|
}
|
||||||
|
if QueryRequest == nil {
|
||||||
|
QueryRequest = make(chan Query)
|
||||||
|
println("Creating channel request")
|
||||||
|
}
|
||||||
|
query("udp", f)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function.
|
func query(n string, f func(*Conn, *Msg)) {
|
||||||
func query(n string, in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
println("in query")
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case q := <-in:
|
case q := <-QueryRequest:
|
||||||
|
println("recveived request")
|
||||||
err := q.Conn.Dial(n)
|
err := q.Conn.Dial(n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out <- Query{Err: err}
|
QueryReply <- Query{Err: err}
|
||||||
}
|
|
||||||
if f == nil {
|
|
||||||
go QueryDefault(q.Conn, q.Msg, out)
|
|
||||||
} else {
|
|
||||||
go f(q.Conn, q.Msg, out)
|
|
||||||
}
|
}
|
||||||
|
go f(q.Conn, q.Msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("not reached")
|
panic("not reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default Handler when none is given.
|
|
||||||
func QueryDefault(d *Conn, m *Msg, q chan Query) {
|
|
||||||
defer d.Close()
|
|
||||||
buf, ok := m.Pack()
|
|
||||||
if !ok {
|
|
||||||
q <- Query{nil, d, ErrPack}
|
|
||||||
}
|
|
||||||
ret, err := d.Exchange(buf, false)
|
|
||||||
if err != nil {
|
|
||||||
q <- Query{nil, d, err}
|
|
||||||
}
|
|
||||||
out := new(Msg)
|
|
||||||
if ok1 := out.Unpack(ret); !ok1 {
|
|
||||||
q <- Query{nil, d, ErrUnpack}
|
|
||||||
}
|
|
||||||
q <- Query{out, d, nil}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple query function that waits for and returns the reply.
|
// Simple query function that waits for and returns the reply.
|
||||||
func QuerySimple(d *Conn, m *Msg) (*Msg, os.Error) {
|
func QuerySimple(d *Conn, m *Msg) (*Msg, os.Error) {
|
||||||
buf, ok := m.Pack()
|
buf, ok := m.Pack()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrPack
|
return nil, ErrPack
|
||||||
}
|
|
||||||
// Dialing should happen in the client
|
|
||||||
|
|
||||||
ret, err := d.Exchange(buf, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
o := new(Msg)
|
|
||||||
if ok := o.Unpack(ret); !ok {
|
|
||||||
return nil, ErrUnpack
|
|
||||||
}
|
|
||||||
return o, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryAndServeTCP listens for incoming requests on channel in and
|
|
||||||
// then calls QueryTCP with f to the handle the request.
|
|
||||||
// It returns a channel on which the response is returned.
|
|
||||||
func QueryAndServeTCP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query {
|
|
||||||
out := make(chan Query)
|
|
||||||
go QueryTCP(in, out, f)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueryAndServeUDP listens for incoming requests on channel in and
|
|
||||||
// then calls QueryUDP with f to the handle the request.
|
|
||||||
// It returns a channel on which the response is returned.
|
|
||||||
func QueryAndServeUDP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query {
|
|
||||||
out := make(chan Query)
|
|
||||||
go QueryUDP(in, out, f)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
/* // alg for querying a list of servers, not sure if we going to keep it
|
|
||||||
for i := 0; i < len(res.Servers); i++ {
|
|
||||||
var d *Conn
|
|
||||||
server := res.Servers[i] + ":" + port
|
|
||||||
t := time.Nanoseconds()
|
|
||||||
if res.Tcp {
|
|
||||||
d, err = Dial("tcp", "", server)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
d, err = Dial("udp", "", server)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inb, err = d.Exchange(sending, false)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
in.Unpack(inb) // Discard error.
|
|
||||||
res.Rtt[server] = time.Nanoseconds() - t
|
|
||||||
d.Close()
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
*/
|
// Dialing should happen in the client
|
||||||
|
|
||||||
|
ret, err := d.Exchange(buf, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
o := new(Msg)
|
||||||
|
if ok := o.Unpack(ret); !ok {
|
||||||
|
return nil, ErrUnpack
|
||||||
|
}
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue