diff --git a/TODO b/TODO index f8c4b1f0..1ab41be0 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,12 @@ - Guidelines for the API: o symmetrical, client side should be mirrored in the server o clean, small API o fast data structures (rb-tree, when they come available) o api-use should be self documenting +o multiple queries in api o make questions fqdns -- add last dot -o zone structure -- only as rb-tree +o zone structure -- only as rb-tree or other radix tree o compression (only ownernames?) o Key2DS, also for offline keys -- need to parse them ofcourse diff --git a/_examples/q/q.go b/_examples/q/q.go index c21d1c1b..2f7bbd43 100644 --- a/_examples/q/q.go +++ b/_examples/q/q.go @@ -89,10 +89,10 @@ Flags: m.MsgHdr.RecursionDesired = *rd m.Question = make([]dns.Question, 1) if *dnssec || *nsid { - opt := new(dns.RR_OPT) + opt := new(dns.RR_OPT) opt.SetDo() - opt.SetVersion(0) - opt.SetUDPSize(dns.DefaultMsgSize) + opt.SetVersion(0) + opt.SetUDPSize(dns.DefaultMsgSize) if *nsid { opt.SetNsid("") } @@ -129,7 +129,7 @@ func shortMsg(in *dns.Msg) *dns.Msg { for i := 0; i < len(in.Extra); i++ { in.Extra[i] = shortRR(in.Extra[i]) } - return in + return in } func shortRR(r dns.RR) dns.RR { @@ -138,8 +138,8 @@ func shortRR(r dns.RR) dns.RR { t.PublicKey = "( ... )" case *dns.RR_RRSIG: t.Signature = "( ... )" - case *dns.RR_NSEC3: - t.Salt = "-" // nobody cares + case *dns.RR_NSEC3: + t.Salt = "-" // nobody cares } return r } diff --git a/dns.go b/dns.go index e1e124f7..3af2a9e0 100644 --- a/dns.go +++ b/dns.go @@ -86,7 +86,11 @@ type Conn struct { // The remote port number of the connection. Port int + // Remove server (for resolver) + RemoteAddr string + // If TSIG is used, this holds all the information. + // If unused is must be nil. Tsig *Tsig // Timeout in sec before giving up on a connection. @@ -366,7 +370,6 @@ func (d *Conn) Exchange(request []byte, nosend bool) (reply []byte, err os.Error return nil, err } } - // Layer violation to save memory. Its okay then... reply = d.NewBuffer() n, err = d.Read(reply) if err != nil { diff --git a/msg.go b/msg.go index 1cf8bc17..3f7c2881 100644 --- a/msg.go +++ b/msg.go @@ -44,6 +44,7 @@ var ( ErrSigGen os.Error = &Error{Error: "bad signature generation"} ErrAuth os.Error = &Error{Error: "bad authentication"} ErrXfrSoa os.Error = &Error{Error: "no SOA seen"} + ErrHandle os.Error = &Error{Error: "the handle is nill"} ) // A manually-unpacked version of (id, bits). diff --git a/resolver.go b/resolver.go index 8dd0dd0d..ff956925 100644 --- a/resolver.go +++ b/resolver.go @@ -8,9 +8,58 @@ package dns import ( "os" + "net" "time" ) +type Query struct { + Msg *Msg + Conn *Conn + Err os.Error +} + +// A query implementation that is asyn. and concurrent. Is also +// completely mirrors the server side implementation + +func QueryTCP(in, out chan Query, f func(*Conn, *Msg, chan Query)) { + query("tcp", in, out, f) +} + +func QueryUDP(in, out chan Query, f func(*Conn, *Msg, chan Query)) { + query("udp", in, out, f) +} + +func query(n string, in, out chan Query, f func(*Conn, *Msg, chan Query)) { + for { + select { + case q := <-in: + c, err := net.Dial(n, "", q.Conn.RemoteAddr) + if err != nil { + //out <- nil + } + if n == "tcp" { + q.Conn.SetTCPConn(c.(*net.TCPConn), nil) + } else { + q.Conn.SetUDPConn(c.(*net.UDPConn), nil) + } + go f(q.Conn, q.Msg, out) + } + } + panic("not reached") +} + +func QueryAndServeTCP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query { + out := make(chan Query) + go QueryTCP(in, out, f) + return out +} + +func QueryAndServeUDP(in chan Query, f func(*Conn, *Msg, chan Query)) chan Query { + out := make(chan Query) + go QueryUDP(in, out, f) + return out +} + type Resolver struct { Servers []string // servers to use Search []string // suffixes to append to local name (not implemented) @@ -47,7 +96,7 @@ func (res *Resolver) QueryTsig(q *Msg, tsig *Tsig) (d *Msg, err os.Error) { } for i := 0; i < len(res.Servers); i++ { - var d *Conn + var d *Conn server := res.Servers[i] + ":" + port t := time.Nanoseconds() if res.Tcp { @@ -68,7 +117,7 @@ func (res *Resolver) QueryTsig(q *Msg, tsig *Tsig) (d *Msg, err os.Error) { } in.Unpack(inb) // Discard error. res.Rtt[server] = time.Nanoseconds() - t - d.Close() + d.Close() break } if err != nil { @@ -102,7 +151,7 @@ func (res *Resolver) XfrTsig(q *Msg, t *Tsig, m chan Xfr) { Server: for i := 0; i < len(res.Servers); i++ { server := res.Servers[i] + ":" + port - d, err := Dial("tcp", "", server) + d, err := Dial("tcp", "", server) if err != nil { continue Server } diff --git a/server.go b/server.go index 838f3bfa..d2205e93 100644 --- a/server.go +++ b/server.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// DNS server implementation +// DNS server implementation. package dns @@ -67,7 +67,7 @@ func HandleTCP(l *net.TCPListener, f func(*Conn, *Msg)) os.Error { // connections. The function f may not be nil. func ListenAndServeTCP(addr string, f func(*Conn, *Msg)) os.Error { if f == nil { - return &Error{Error: "The handle function may not be nil"} + return ErrHandle } a, err := net.ResolveTCPAddr(addr) if err != nil {