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
|
||||
* HIP RR (needs list of domain names, need slice stuff for that)
|
||||
* Is subdomain, is glue helper functions for this kind of stuff
|
||||
* Make QuerySimple even simpler??
|
||||
|
||||
Issues:
|
||||
* FunkenSturm is kaput.
|
||||
* Check the network order, it works now, but this is on Intel??
|
||||
* Make the testsuite work with public DNS servers
|
||||
* pack/Unpack smaller. EDNS 'n stuff can be folded in
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
func main() {
|
||||
var dnssec *bool = flag.Bool("dnssec", false, "Request DNSSEC records")
|
||||
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 ad *bool = flag.Bool("ad", false, "Set AD flag in query")
|
||||
var cd *bool = flag.Bool("cd", false, "Set CD flag in query")
|
||||
|
@ -24,8 +24,8 @@ func main() {
|
|||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
// Need to think about it... Config
|
||||
c, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
// Need to think about it... Config
|
||||
c, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
nameserver := "@" + c.Servers[0]
|
||||
qtype := uint16(dns.TypeA) // Default qtype
|
||||
qclass := uint16(dns.ClassINET) // Default qclass
|
||||
|
@ -70,9 +70,11 @@ Flags:
|
|||
|
||||
nameserver = string([]byte(nameserver)[1:]) // chop off @
|
||||
|
||||
d := new(dns.Conn)
|
||||
d.RemoteAddr = nameserver + ":" + *port
|
||||
d.Attempts = 1
|
||||
// Port stuff does not work
|
||||
d := new(dns.Conn)
|
||||
// d.RemoteAddr = nameserver + ":" + *port
|
||||
d.RemoteAddr = nameserver // works with /etc/resolv.conf
|
||||
d.Attempts = 1
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.MsgHdr.Authoritative = *aa
|
||||
|
@ -92,35 +94,65 @@ Flags:
|
|||
m.Extra[0] = opt
|
||||
}
|
||||
|
||||
in := make(chan dns.Query)
|
||||
var out chan dns.Query
|
||||
if *tcp {
|
||||
out = dns.QueryAndServeTCP(in, nil)
|
||||
} else {
|
||||
out = dns.QueryAndServeUDP(in, nil)
|
||||
}
|
||||
err := make(chan os.Error)
|
||||
if *tcp {
|
||||
go query(err, "tcp")
|
||||
} else {
|
||||
go query(err, "udp")
|
||||
}
|
||||
|
||||
for _, v := range qname {
|
||||
m.Question[0] = dns.Question{v, qtype, qclass}
|
||||
m.Id = dns.Id()
|
||||
in <- dns.Query{Msg: m, Conn: d}
|
||||
dns.QueryReply = make(chan dns.Query)
|
||||
dns.QueryRequest = make(chan dns.Query)
|
||||
// Start the quering in a closure
|
||||
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
|
||||
|
||||
if r.Msg != nil {
|
||||
if r.Msg.Id != m.Id {
|
||||
fmt.Printf("Id mismatch\n")
|
||||
i :=0
|
||||
for {
|
||||
select {
|
||||
case r := <-dns.QueryReply:
|
||||
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 {
|
||||
r.Msg = shortMsg(r.Msg)
|
||||
}
|
||||
fmt.Printf("%v", r.Msg)
|
||||
} else {
|
||||
fmt.Printf("%v\n", r.Err.String())
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
func shortMsg(in *dns.Msg) *dns.Msg {
|
||||
for i := 0; i < len(in.Answer); i++ {
|
||||
|
|
|
@ -5,41 +5,66 @@ package main
|
|||
// zone contents.
|
||||
// This zone is then checked cryptographically is
|
||||
// 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
|
||||
// it validates it writes this record to disk and
|
||||
// this new key will be used in future validations.
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"os"
|
||||
"os/signal"
|
||||
"fmt"
|
||||
"dns"
|
||||
)
|
||||
|
||||
// Static amount of RRs...
|
||||
type zone struct {
|
||||
name string
|
||||
rrs [10000]dns.RR
|
||||
size int
|
||||
name string
|
||||
rrs [10000]dns.RR
|
||||
size int
|
||||
}
|
||||
|
||||
var Zone zone
|
||||
|
||||
func handle(d *dns.Conn, i *dns.Msg) {
|
||||
if i.MsgHdr.Response == true {
|
||||
return
|
||||
}
|
||||
handleNotify(d, i)
|
||||
handleXfr(d, i)
|
||||
/* send response here, how ??? */
|
||||
if i.MsgHdr.Response == true {
|
||||
return
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
case "tcp":
|
||||
err := dns.ListenAndServeTCP(addr, handle)
|
||||
err := dns.QueryAndServeTCP(qhandle)
|
||||
e <- err
|
||||
case "udp":
|
||||
err := dns.ListenAndServeUDP(addr, handle)
|
||||
err := dns.QueryAndServeUDP(qhandle)
|
||||
e <- err
|
||||
}
|
||||
return
|
||||
|
@ -47,6 +72,12 @@ func listen(addr string, e chan os.Error, tcp string) {
|
|||
|
||||
func main() {
|
||||
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("[::1]:8053", err, "tcp")
|
||||
go listen("127.0.0.1:8053", err, "udp")
|
||||
|
@ -61,6 +92,9 @@ forever:
|
|||
case <-signal.Incoming:
|
||||
fmt.Printf("Signal received, stopping")
|
||||
break forever
|
||||
case q := <-dns.QueryReply:
|
||||
var _ = q
|
||||
/* ... */
|
||||
}
|
||||
}
|
||||
close(err)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
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.
|
||||
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.
|
||||
// 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) {
|
||||
// err := ListenAndServeUDP(addr, handle)
|
||||
|
@ -433,6 +433,25 @@ func (d *Conn) Exchange(request []byte, nosend bool) (reply []byte, err os.Error
|
|||
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 {
|
||||
Header() *RR_Header
|
||||
String() string
|
||||
|
|
166
resolver.go
166
resolver.go
|
@ -10,132 +10,92 @@ import (
|
|||
"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.
|
||||
type Query struct {
|
||||
// The query message.
|
||||
Msg *Msg
|
||||
// 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.
|
||||
Conn *Conn
|
||||
// Any error when querying is returned in Err. The caller
|
||||
// should just set this to nil.
|
||||
Err os.Error
|
||||
// Query time in here?
|
||||
//
|
||||
Err os.Error
|
||||
}
|
||||
|
||||
// QueryUDP handles one query. It reads an incoming request from
|
||||
// the in channel. The function f is executed in a seperate
|
||||
// goroutine and performs the actual UDP query.
|
||||
func QueryUDP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
||||
query("udp", in, out, f)
|
||||
// QueryAndServeTCP listens for incoming requests on channel in and
|
||||
// then calls f.
|
||||
// The function f is executed in a seperate goroutine and performs the actual
|
||||
// TCP query.
|
||||
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
|
||||
// the in channel. The function f is executed in a seperate
|
||||
// goroutine and performas the actual TCP query.
|
||||
func QueryTCP(in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
||||
query("tcp", in, out, f)
|
||||
// QueryAndServeUDP listens for incoming requests on channel in and
|
||||
// then calls f.
|
||||
// The function f is executed in a seperate goroutine and performs the actual
|
||||
// UDP query.
|
||||
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, in, out chan Query, f func(*Conn, *Msg, chan Query)) {
|
||||
func query(n string, f func(*Conn, *Msg)) {
|
||||
println("in query")
|
||||
for {
|
||||
select {
|
||||
case q := <-in:
|
||||
case q := <-QueryRequest:
|
||||
println("recveived request")
|
||||
err := q.Conn.Dial(n)
|
||||
if err != nil {
|
||||
out <- Query{Err: err}
|
||||
}
|
||||
if f == nil {
|
||||
go QueryDefault(q.Conn, q.Msg, out)
|
||||
} else {
|
||||
go f(q.Conn, q.Msg, out)
|
||||
QueryReply <- Query{Err: err}
|
||||
}
|
||||
go f(q.Conn, q.Msg)
|
||||
}
|
||||
}
|
||||
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.
|
||||
func QuerySimple(d *Conn, m *Msg) (*Msg, os.Error) {
|
||||
buf, ok := m.Pack()
|
||||
if !ok {
|
||||
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
|
||||
buf, ok := m.Pack()
|
||||
if !ok {
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue