2011-04-13 05:44:56 +10:00
|
|
|
package dns
|
|
|
|
|
|
|
|
// A concurrent client implementation.
|
|
|
|
|
|
|
|
import (
|
2011-04-16 07:55:27 +10:00
|
|
|
"io"
|
|
|
|
"net"
|
2012-01-20 22:13:47 +11:00
|
|
|
"time"
|
2011-04-13 05:44:56 +10:00
|
|
|
)
|
|
|
|
|
|
|
|
type QueryHandler interface {
|
2011-04-13 06:21:09 +10:00
|
|
|
QueryDNS(w RequestWriter, q *Msg)
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
2011-08-01 21:15:15 +10:00
|
|
|
// The RequestWriter interface is used by a DNS query handler to
|
|
|
|
// construct a DNS request.
|
2011-04-13 05:44:56 +10:00
|
|
|
type RequestWriter interface {
|
2012-05-08 21:51:12 +10:00
|
|
|
// RemoteAddr returns the net.Addr of the server
|
|
|
|
RemoteAddr() net.Addr
|
|
|
|
// TsigStatus returns the TSIG validation status.
|
|
|
|
TsigStatus() error
|
|
|
|
// Write returns the request message and the reply back to the client (i.e. your Go code).
|
2012-03-05 07:00:09 +11:00
|
|
|
Write(*Msg) error
|
2012-03-05 00:53:57 +11:00
|
|
|
// Send sends the message to the server.
|
2011-11-03 09:06:54 +11:00
|
|
|
Send(*Msg) error
|
2012-03-05 00:53:57 +11:00
|
|
|
// Receive waits for the reply of the servers.
|
2011-11-03 09:06:54 +11:00
|
|
|
Receive() (*Msg, error)
|
2012-03-05 00:53:57 +11:00
|
|
|
// Close closes the connection with the server.
|
2011-11-03 09:06:54 +11:00
|
|
|
Close() error
|
2012-05-05 07:18:29 +10:00
|
|
|
// Dials calls the server.
|
2011-11-03 09:06:54 +11:00
|
|
|
Dial() error
|
2011-04-13 06:21:09 +10:00
|
|
|
}
|
|
|
|
|
2011-04-15 06:11:41 +10:00
|
|
|
// hijacked connections...?
|
2011-04-13 06:39:38 +10:00
|
|
|
type reply struct {
|
2011-04-19 06:08:12 +10:00
|
|
|
client *Client
|
|
|
|
addr string
|
|
|
|
req *Msg
|
|
|
|
conn net.Conn
|
2011-04-23 00:37:26 +10:00
|
|
|
tsigRequestMAC string
|
2011-04-19 06:08:12 +10:00
|
|
|
tsigTimersOnly bool
|
2012-03-05 00:47:20 +11:00
|
|
|
tsigStatus error
|
2012-05-05 07:18:29 +10:00
|
|
|
rtt time.Duration
|
|
|
|
t time.Time
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
|
|
|
|
2012-02-27 07:33:50 +11:00
|
|
|
// A Request is a incoming message from a Client.
|
2011-04-18 05:56:40 +10:00
|
|
|
type Request struct {
|
|
|
|
Request *Msg
|
|
|
|
Addr string
|
|
|
|
Client *Client
|
2011-04-13 06:21:09 +10:00
|
|
|
}
|
2011-04-13 05:44:56 +10:00
|
|
|
|
|
|
|
// QueryMux is an DNS request multiplexer. It matches the
|
|
|
|
// zone name of each incoming request against a list of
|
|
|
|
// registered patterns add calls the handler for the pattern
|
|
|
|
// that most closely matches the zone name.
|
|
|
|
type QueryMux struct {
|
2011-04-13 06:21:09 +10:00
|
|
|
m map[string]QueryHandler
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewQueryMux allocates and returns a new QueryMux.
|
|
|
|
func NewQueryMux() *QueryMux { return &QueryMux{make(map[string]QueryHandler)} }
|
|
|
|
|
|
|
|
// DefaultQueryMux is the default QueryMux used by Query.
|
|
|
|
var DefaultQueryMux = NewQueryMux()
|
|
|
|
|
2011-09-10 22:26:08 +10:00
|
|
|
func newQueryChanSlice() chan *Exchange { return make(chan *Exchange) }
|
|
|
|
func newQueryChan() chan *Request { return make(chan *Request) }
|
2011-04-14 04:41:16 +10:00
|
|
|
|
2011-07-06 05:08:22 +10:00
|
|
|
// Default channels to use for the resolver
|
2011-09-10 22:26:08 +10:00
|
|
|
var (
|
2012-05-22 16:47:47 +10:00
|
|
|
// QueryReply is the channel on which the replies are
|
|
|
|
// coming back. Is it a channel of *Exchange. The original
|
2011-09-10 22:26:08 +10:00
|
|
|
// question is included with the answer.
|
2012-05-22 06:06:58 +10:00
|
|
|
QueryReply = newQueryChanSlice()
|
2012-05-22 16:47:47 +10:00
|
|
|
// QueryRequest is the channel were you can send the questions to.
|
|
|
|
// It is a channel of *Request
|
2012-05-22 06:06:58 +10:00
|
|
|
QueryRequest = newQueryChan()
|
2011-09-10 22:26:08 +10:00
|
|
|
)
|
2011-04-14 04:41:16 +10:00
|
|
|
|
2011-04-13 05:44:56 +10:00
|
|
|
// The HandlerQueryFunc type is an adapter to allow the use of
|
|
|
|
// ordinary functions as DNS query handlers. If f is a function
|
|
|
|
// with the appropriate signature, HandlerQueryFunc(f) is a
|
2011-04-15 06:11:41 +10:00
|
|
|
// QueryHandler object that calls f.
|
2011-04-13 05:44:56 +10:00
|
|
|
type HandlerQueryFunc func(RequestWriter, *Msg)
|
|
|
|
|
2012-05-06 04:47:23 +10:00
|
|
|
// QueryDNS calls f(w, reg).
|
2011-04-13 05:44:56 +10:00
|
|
|
func (f HandlerQueryFunc) QueryDNS(w RequestWriter, r *Msg) {
|
2011-04-15 06:11:41 +10:00
|
|
|
go f(w, r)
|
|
|
|
}
|
|
|
|
|
2012-03-27 08:15:15 +11:00
|
|
|
// HandleQueryFunc registers the handler with the given pattern in the
|
2012-05-08 22:01:58 +10:00
|
|
|
// DefaultQueryMux. See HandleQuery for an example.
|
2011-04-15 06:11:41 +10:00
|
|
|
func HandleQueryFunc(pattern string, handler func(RequestWriter, *Msg)) {
|
2012-03-27 08:15:15 +11:00
|
|
|
DefaultQueryMux.HandleFunc(pattern, handler)
|
|
|
|
}
|
|
|
|
|
2012-05-08 22:01:58 +10:00
|
|
|
// HandleQuery registers the handler in the DefaultQueryMux. The pattern is
|
|
|
|
// the name of a zone, or "." which can be used as a catch-all. Basic use pattern
|
|
|
|
// (sans error checking) for setting up a query handler:
|
|
|
|
//
|
|
|
|
// func myhandler(w dns.RequestWriter, m *dns.Msg) {
|
|
|
|
// w.Send(m) // send the message m to server specified in the Do() call
|
|
|
|
// r, _ := w.Receive() // wait for a response
|
|
|
|
// w.Close() // close connection with the server
|
2012-05-22 16:47:47 +10:00
|
|
|
// w.Write(r) // write the received answer back to the client
|
2012-05-08 22:01:58 +10:00
|
|
|
// }
|
|
|
|
//
|
|
|
|
// func main() {
|
|
|
|
// dns.HandleQuery(".", myhandler)
|
2012-05-22 16:51:30 +10:00
|
|
|
// dns.ListenAndQuery(nil)
|
2012-05-08 22:01:58 +10:00
|
|
|
// m := new(dns.Msg)
|
2012-05-26 18:28:32 +10:00
|
|
|
// c := new(dns.Client)
|
2012-05-08 22:01:58 +10:00
|
|
|
// m.SetQuestion("miek.nl.", TypeMX)
|
|
|
|
// c.Do(m, "127.0.0.1:53")
|
|
|
|
// // ...
|
2012-05-23 04:14:15 +10:00
|
|
|
// r := <- c.Reply // or <- dns.QueryReply, when using the defaults
|
2012-05-08 22:01:58 +10:00
|
|
|
// }
|
2012-03-27 08:15:15 +11:00
|
|
|
func HandleQuery(pattern string, handler HandlerQueryFunc) {
|
|
|
|
DefaultQueryMux.Handle(pattern, handler)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandleQueryRemove deregisters the handle with the given pattern
|
|
|
|
// in the DefaultQueryMux.
|
|
|
|
func HandleQueryRemove(pattern string) {
|
|
|
|
DefaultQueryMux.HandleRemove(pattern)
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// reusing zoneMatch from server.go
|
|
|
|
func (mux *QueryMux) match(zone string) QueryHandler {
|
2011-04-13 06:21:09 +10:00
|
|
|
var h QueryHandler
|
|
|
|
var n = 0
|
|
|
|
for k, v := range mux.m {
|
|
|
|
if !zoneMatch(k, zone) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if h == nil || len(k) > n {
|
|
|
|
n = len(k)
|
|
|
|
h = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return h
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
func (mux *QueryMux) Handle(pattern string, handler QueryHandler) {
|
2011-04-13 06:21:09 +10:00
|
|
|
if pattern == "" {
|
|
|
|
panic("dns: invalid pattern " + pattern)
|
|
|
|
}
|
2012-05-23 04:14:15 +10:00
|
|
|
// check is domainname TODO(mg)
|
2011-07-05 06:27:23 +10:00
|
|
|
mux.m[pattern] = handler
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
2012-03-27 08:15:15 +11:00
|
|
|
// HandleRemove deregisters the handler with given pattern.
|
|
|
|
func (mux *QueryMux) HandleRemove(pattern string) {
|
|
|
|
delete(mux.m, pattern)
|
|
|
|
}
|
|
|
|
|
|
|
|
// HandleFunc ...
|
|
|
|
func (mux *QueryMux) HandleFunc(pattern string, handler func(RequestWriter, *Msg)) {
|
2011-04-13 06:21:09 +10:00
|
|
|
mux.Handle(pattern, HandlerQueryFunc(handler))
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
2011-04-18 05:56:40 +10:00
|
|
|
func (mux *QueryMux) QueryDNS(w RequestWriter, r *Msg) {
|
|
|
|
h := mux.match(r.Question[0].Name)
|
2011-04-13 06:21:09 +10:00
|
|
|
if h == nil {
|
2011-07-24 07:43:43 +10:00
|
|
|
panic("dns: no handler found for " + r.Question[0].Name)
|
2011-04-13 06:21:09 +10:00
|
|
|
}
|
2011-04-18 05:56:40 +10:00
|
|
|
h.QueryDNS(w, r)
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
2012-05-26 18:24:47 +10:00
|
|
|
// A nil Client is usable.
|
2011-04-13 05:44:56 +10:00
|
|
|
type Client struct {
|
2012-05-26 18:24:47 +10:00
|
|
|
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "", is UDP)
|
|
|
|
Attempts int // number of attempts, if not set defaults to 1
|
2011-04-19 06:08:12 +10:00
|
|
|
Retry bool // retry with TCP
|
2012-05-22 04:58:41 +10:00
|
|
|
Request chan *Request // read DNS request from this channel
|
2012-05-22 16:48:26 +10:00
|
|
|
Reply chan *Exchange // write replies to this channel
|
2012-05-26 18:24:47 +10:00
|
|
|
ReadTimeout time.Duration // the net.Conn.SetReadTimeout value for new connections (ns), defauls to 2 * 1e9
|
|
|
|
WriteTimeout time.Duration // the net.Conn.SetWriteTimeout value for new connections (ns), defauls to 2 * 1e9
|
2011-04-19 06:08:12 +10:00
|
|
|
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>
|
2011-09-10 22:26:08 +10:00
|
|
|
Hijacked net.Conn // if set the calling code takes care of the connection
|
2011-07-24 07:43:43 +10:00
|
|
|
// LocalAddr string // Local address to use
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
type Query struct {
|
2012-05-22 16:48:26 +10:00
|
|
|
Request chan *Request // read DNS request from this channel
|
|
|
|
Handler QueryHandler // handler to invoke, dns.DefaultQueryMux if nil
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
|
|
|
|
2011-11-03 09:06:54 +11:00
|
|
|
func (q *Query) Query() error {
|
2011-04-18 05:56:40 +10:00
|
|
|
handler := q.Handler
|
2011-04-13 06:21:09 +10:00
|
|
|
if handler == nil {
|
|
|
|
handler = DefaultQueryMux
|
|
|
|
}
|
2011-04-15 06:11:41 +10:00
|
|
|
for {
|
|
|
|
select {
|
2012-05-22 04:58:41 +10:00
|
|
|
case in := <-q.Request:
|
2011-04-15 06:11:41 +10:00
|
|
|
w := new(reply)
|
2011-04-18 05:56:40 +10:00
|
|
|
w.req = in.Request
|
|
|
|
w.addr = in.Addr
|
|
|
|
w.client = in.Client
|
|
|
|
handler.QueryDNS(w, in.Request)
|
2011-04-15 06:11:41 +10:00
|
|
|
}
|
|
|
|
}
|
2011-04-13 06:21:09 +10:00
|
|
|
return nil
|
2011-04-13 05:44:56 +10:00
|
|
|
}
|
|
|
|
|
2011-11-03 09:06:54 +11:00
|
|
|
func (q *Query) ListenAndQuery() error {
|
2012-05-22 04:58:41 +10:00
|
|
|
if q.Request == nil {
|
2012-05-22 06:06:58 +10:00
|
|
|
q.Request = QueryRequest
|
2011-04-15 06:11:41 +10:00
|
|
|
}
|
2011-04-18 05:56:40 +10:00
|
|
|
return q.Query()
|
|
|
|
}
|
|
|
|
|
2012-05-22 04:58:41 +10:00
|
|
|
// ListenAndQuery starts the listener for firing off the queries.
|
2012-05-22 16:47:47 +10:00
|
|
|
// If handler is nil DefaultQueryMux is used. The default request
|
|
|
|
// channel (QueryRequest) is used for requesting queries.
|
2012-05-22 04:58:41 +10:00
|
|
|
func ListenAndQuery(handler QueryHandler) {
|
|
|
|
q := &Query{Request: nil, Handler: handler}
|
|
|
|
go q.ListenAndQuery()
|
|
|
|
}
|
|
|
|
|
2012-05-22 16:47:47 +10:00
|
|
|
// ListenAndQueryRequest starts the listener for firing off queries. If
|
|
|
|
// request is nil QueryRequest is used. If handler is nil DefaultQueryMux is used.
|
2012-05-22 04:58:41 +10:00
|
|
|
func ListenAndQueryRequest(request chan *Request, handler QueryHandler) {
|
|
|
|
q := &Query{Request: request, Handler: handler}
|
2011-04-18 05:56:40 +10:00
|
|
|
go q.ListenAndQuery()
|
2011-04-15 06:11:41 +10:00
|
|
|
}
|
|
|
|
|
2011-09-11 08:31:03 +10:00
|
|
|
// Write returns the original question and the answer on the
|
|
|
|
// reply channel of the client.
|
2012-03-05 07:00:09 +11:00
|
|
|
func (w *reply) Write(m *Msg) error {
|
2012-05-06 01:37:33 +10:00
|
|
|
if w.conn == nil {
|
2012-05-26 18:24:47 +10:00
|
|
|
if w.Client().Reply == nil {
|
|
|
|
QueryReply <- &Exchange{Request: w.req, Reply: m, Rtt: w.rtt}
|
|
|
|
return nil
|
|
|
|
}
|
2012-05-22 06:06:58 +10:00
|
|
|
w.Client().Reply <- &Exchange{Request: w.req, Reply: m, Rtt: w.rtt}
|
2012-05-06 01:37:33 +10:00
|
|
|
} else {
|
2012-05-26 18:24:47 +10:00
|
|
|
if w.Client().Reply == nil {
|
|
|
|
QueryReply <- &Exchange{Request: w.req, Reply: m, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr()}
|
|
|
|
return nil
|
|
|
|
}
|
2012-05-22 06:06:58 +10:00
|
|
|
w.Client().Reply <- &Exchange{Request: w.req, Reply: m, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr()}
|
2012-05-06 01:37:33 +10:00
|
|
|
}
|
2012-03-05 07:00:09 +11:00
|
|
|
return nil
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
|
|
|
|
2012-05-08 21:51:12 +10:00
|
|
|
func (w *reply) RemoteAddr() net.Addr {
|
|
|
|
if w.conn == nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
return w.conn.RemoteAddr()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2011-07-05 05:38:50 +10:00
|
|
|
// Do performs an asynchronous query. The result is returned on the
|
2012-05-22 16:47:47 +10:00
|
|
|
// channel c.Reply. Basic use pattern for
|
2012-05-06 04:47:23 +10:00
|
|
|
// sending message m to the server listening on port 53 on localhost
|
|
|
|
//
|
2012-05-22 16:47:47 +10:00
|
|
|
// c.Do(m, "127.0.0.1:53")
|
|
|
|
// r := <- c.Reply
|
2012-05-06 04:47:23 +10:00
|
|
|
//
|
2012-05-22 16:47:47 +10:00
|
|
|
// r is of type *Exchange.
|
2011-04-18 05:56:40 +10:00
|
|
|
func (c *Client) Do(m *Msg, a string) {
|
2012-05-22 04:58:41 +10:00
|
|
|
c.Request <- &Request{Client: c, Addr: a, Request: m}
|
2011-04-15 06:11:41 +10:00
|
|
|
}
|
|
|
|
|
2012-05-06 00:09:57 +10:00
|
|
|
// exchangeBuffer performs a synchronous query. It sends the buffer m to the
|
2011-12-17 05:35:37 +11:00
|
|
|
// address contained in a.
|
2012-05-06 00:09:57 +10:00
|
|
|
func (c *Client) exchangeBuffer(inbuf []byte, a string, outbuf []byte) (n int, w *reply, err error) {
|
|
|
|
w = new(reply)
|
2011-04-18 17:28:56 +10:00
|
|
|
w.client = c
|
|
|
|
w.addr = a
|
2011-09-10 22:26:08 +10:00
|
|
|
if c.Hijacked == nil {
|
|
|
|
if err = w.Dial(); err != nil {
|
2012-05-06 00:09:57 +10:00
|
|
|
return 0, w, err
|
2011-09-10 22:26:08 +10:00
|
|
|
}
|
2011-08-09 00:29:13 +10:00
|
|
|
defer w.Close()
|
2011-08-08 21:10:35 +10:00
|
|
|
}
|
2011-09-10 22:26:08 +10:00
|
|
|
if c.Hijacked != nil {
|
|
|
|
w.conn = c.Hijacked
|
|
|
|
}
|
2012-05-05 07:18:29 +10:00
|
|
|
w.t = time.Now()
|
2011-08-08 21:10:35 +10:00
|
|
|
if n, err = w.writeClient(inbuf); err != nil {
|
2012-05-06 00:09:57 +10:00
|
|
|
return 0, w, err
|
2011-04-18 17:28:56 +10:00
|
|
|
}
|
2011-08-08 21:10:35 +10:00
|
|
|
if n, err = w.readClient(outbuf); err != nil {
|
2012-05-06 00:09:57 +10:00
|
|
|
return n, w, err
|
2011-04-18 17:28:56 +10:00
|
|
|
}
|
2012-05-05 07:18:29 +10:00
|
|
|
w.rtt = time.Since(w.t)
|
2012-05-06 00:09:57 +10:00
|
|
|
return n, w, nil
|
2011-08-04 19:27:56 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// Exchange performs an synchronous query. It sends the message m to the address
|
2012-05-06 04:47:23 +10:00
|
|
|
// contained in a and waits for an reply. Basic use pattern with a *Client:
|
|
|
|
//
|
2012-05-26 18:28:32 +10:00
|
|
|
// c := new(dns.Client)
|
2012-05-07 23:50:13 +10:00
|
|
|
// in, err := c.Exchange(message, "127.0.0.1:53")
|
2012-05-07 23:53:35 +10:00
|
|
|
//
|
2012-05-22 16:47:47 +10:00
|
|
|
// See Client.ExchangeRtt(...) to get the round trip time.
|
2012-05-07 23:50:13 +10:00
|
|
|
func (c *Client) Exchange(m *Msg, a string) (r *Msg, err error) {
|
2012-05-22 16:47:47 +10:00
|
|
|
r, _, _, err = c.ExchangeRtt(m, a)
|
2012-05-07 23:50:13 +10:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2012-05-22 16:47:47 +10:00
|
|
|
// ExchangeRtt performs an synchronous query. It sends the message m to the address
|
2012-05-07 23:50:13 +10:00
|
|
|
// contained in a and waits for an reply. Basic use pattern with a *Client:
|
|
|
|
//
|
2012-05-26 18:28:32 +10:00
|
|
|
// c := new(dns.Client)
|
2012-05-22 16:47:47 +10:00
|
|
|
// in, rtt, addr, err := c.ExchangeRtt(message, "127.0.0.1:53")
|
2012-05-06 04:47:23 +10:00
|
|
|
//
|
|
|
|
// The 'addr' return value is superfluous in this case, but it is here to retain symmetry
|
|
|
|
// with the asynchronous call, see Client.Do().
|
2012-05-22 16:47:47 +10:00
|
|
|
func (c *Client) ExchangeRtt(m *Msg, a string) (r *Msg, rtt time.Duration, addr net.Addr, err error) {
|
2011-08-08 21:10:35 +10:00
|
|
|
var n int
|
2012-05-06 00:09:57 +10:00
|
|
|
var w *reply
|
2011-08-04 19:27:56 +10:00
|
|
|
out, ok := m.Pack()
|
|
|
|
if !ok {
|
2012-05-06 01:37:33 +10:00
|
|
|
return nil, 0, nil, ErrPack
|
2011-08-04 19:27:56 +10:00
|
|
|
}
|
2011-09-10 22:26:08 +10:00
|
|
|
var in []byte
|
|
|
|
switch c.Net {
|
2012-05-23 04:15:30 +10:00
|
|
|
case "tcp", "tcp4", "tcp6":
|
2011-09-10 22:26:08 +10:00
|
|
|
in = make([]byte, MaxMsgSize)
|
2012-05-26 18:24:47 +10:00
|
|
|
case "", "udp", "udp4", "udp6":
|
2012-02-05 21:33:55 +11:00
|
|
|
size := UDPMsgSize
|
|
|
|
for _, r := range m.Extra {
|
|
|
|
if r.Header().Rrtype == TypeOPT {
|
|
|
|
size = int(r.(*RR_OPT).UDPSize())
|
|
|
|
}
|
|
|
|
}
|
2012-01-29 10:20:56 +11:00
|
|
|
in = make([]byte, size)
|
2011-09-10 22:26:08 +10:00
|
|
|
}
|
2012-05-06 00:09:57 +10:00
|
|
|
if n, w, err = c.exchangeBuffer(out, a, in); err != nil {
|
2012-05-06 01:37:33 +10:00
|
|
|
return nil, 0, w.conn.RemoteAddr(), err
|
2011-08-08 21:10:35 +10:00
|
|
|
}
|
|
|
|
r = new(Msg)
|
|
|
|
if ok := r.Unpack(in[:n]); !ok {
|
2012-05-06 01:37:33 +10:00
|
|
|
return nil, w.rtt, w.conn.RemoteAddr(), ErrUnpack
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
2012-05-06 01:37:33 +10:00
|
|
|
return r, w.rtt, w.conn.RemoteAddr(), nil
|
2011-04-16 05:42:27 +10:00
|
|
|
}
|
|
|
|
|
2011-09-11 00:50:27 +10:00
|
|
|
// Dial connects to the address addr for the network set in c.Net
|
2011-11-03 09:06:54 +11:00
|
|
|
func (w *reply) Dial() error {
|
2011-08-08 21:10:35 +10:00
|
|
|
conn, err := net.Dial(w.Client().Net, w.addr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
w.conn = conn
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2011-11-03 09:06:54 +11:00
|
|
|
func (w *reply) Receive() (*Msg, error) {
|
2011-04-18 05:56:40 +10:00
|
|
|
var p []byte
|
|
|
|
m := new(Msg)
|
|
|
|
switch w.Client().Net {
|
2011-07-06 04:55:05 +10:00
|
|
|
case "tcp", "tcp4", "tcp6":
|
2011-04-19 02:29:46 +10:00
|
|
|
p = make([]byte, MaxMsgSize)
|
2012-05-26 18:24:47 +10:00
|
|
|
case "", "udp", "udp4", "udp6":
|
2011-04-18 05:56:40 +10:00
|
|
|
p = make([]byte, DefaultMsgSize)
|
2011-04-19 06:08:12 +10:00
|
|
|
}
|
|
|
|
n, err := w.readClient(p)
|
2012-05-05 07:18:29 +10:00
|
|
|
if err != nil || n == 0 {
|
2011-04-19 06:08:12 +10:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
p = p[:n]
|
|
|
|
if ok := m.Unpack(p); !ok {
|
|
|
|
return nil, ErrUnpack
|
|
|
|
}
|
2012-05-05 07:18:29 +10:00
|
|
|
w.rtt = time.Since(w.t)
|
2011-04-23 00:37:26 +10:00
|
|
|
if m.IsTsig() {
|
|
|
|
secret := m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name
|
2012-02-26 07:42:08 +11:00
|
|
|
if _, ok := w.Client().TsigSecret[secret]; !ok {
|
2012-03-05 00:47:20 +11:00
|
|
|
w.tsigStatus = ErrSecret
|
|
|
|
return m, nil
|
2011-04-23 00:37:26 +10:00
|
|
|
}
|
2012-02-26 07:42:08 +11:00
|
|
|
// Need to work on the original message p, as that was used to calculate the tsig.
|
2012-03-05 00:47:20 +11:00
|
|
|
w.tsigStatus = TsigVerify(p, w.Client().TsigSecret[secret], w.tsigRequestMAC, w.tsigTimersOnly)
|
2011-04-23 00:37:26 +10:00
|
|
|
}
|
2011-04-18 05:56:40 +10:00
|
|
|
return m, nil
|
|
|
|
}
|
2011-04-16 07:55:27 +10:00
|
|
|
|
2011-11-03 09:06:54 +11:00
|
|
|
func (w *reply) readClient(p []byte) (n int, err error) {
|
2011-04-18 05:56:40 +10:00
|
|
|
if w.conn == nil {
|
2011-11-03 09:06:54 +11:00
|
|
|
return 0, ErrConnEmpty
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
2012-05-26 18:24:47 +10:00
|
|
|
if len(p) < 1 {
|
|
|
|
return 0, io.ErrShortBuffer
|
|
|
|
}
|
|
|
|
attempts := w.Client().Attempts
|
|
|
|
if attempts == 0 {
|
|
|
|
attempts = 1
|
|
|
|
}
|
2011-04-18 05:56:40 +10:00
|
|
|
switch w.Client().Net {
|
2011-07-06 04:55:05 +10:00
|
|
|
case "tcp", "tcp4", "tcp6":
|
2012-05-26 18:24:47 +10:00
|
|
|
setTimeouts(w)
|
|
|
|
for a := 0; a < attempts; a++ {
|
2012-01-24 06:35:14 +11:00
|
|
|
n, err = w.conn.(*net.TCPConn).Read(p[0:2])
|
|
|
|
if err != nil || n != 2 {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
l, _ := unpackUint16(p[0:2], 0)
|
|
|
|
if l == 0 {
|
|
|
|
return 0, ErrShortRead
|
|
|
|
}
|
|
|
|
if int(l) > len(p) {
|
|
|
|
return int(l), io.ErrShortBuffer
|
|
|
|
}
|
|
|
|
n, err = w.conn.(*net.TCPConn).Read(p[:l])
|
2011-04-19 06:08:12 +10:00
|
|
|
if err != nil {
|
2012-01-24 06:35:14 +11:00
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return n, err
|
2011-04-19 06:08:12 +10:00
|
|
|
}
|
2012-01-24 06:35:14 +11:00
|
|
|
i := n
|
|
|
|
for i < int(l) {
|
|
|
|
j, err := w.conn.(*net.TCPConn).Read(p[i:int(l)])
|
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
// We are half way in our read...
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return i, err
|
|
|
|
}
|
|
|
|
i += j
|
|
|
|
}
|
|
|
|
n = i
|
2011-04-19 06:08:12 +10:00
|
|
|
}
|
2012-05-26 18:24:47 +10:00
|
|
|
case "", "udp", "udp4", "udp6":
|
|
|
|
for a := 0; a < attempts; a++ {
|
|
|
|
setTimeouts(w)
|
2012-01-24 06:35:14 +11:00
|
|
|
n, _, err = w.conn.(*net.UDPConn).ReadFromUDP(p)
|
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
2011-04-17 18:54:34 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
2011-04-16 07:55:27 +10:00
|
|
|
}
|
|
|
|
|
2011-09-11 09:10:47 +10:00
|
|
|
// Send sends a dns msg to the address specified in w.
|
2011-04-19 06:08:12 +10:00
|
|
|
// If the message m contains a TSIG record the transaction
|
|
|
|
// signature is calculated.
|
2012-03-03 07:19:37 +11:00
|
|
|
func (w *reply) Send(m *Msg) (err error) {
|
|
|
|
var out []byte
|
2011-04-19 06:08:12 +10:00
|
|
|
if m.IsTsig() {
|
2012-03-03 07:19:37 +11:00
|
|
|
mac := ""
|
2012-03-02 08:40:34 +11:00
|
|
|
name := m.Extra[len(m.Extra)-1].(*RR_TSIG).Hdr.Name
|
|
|
|
if _, ok := w.Client().TsigSecret[name]; !ok {
|
2011-09-11 00:50:27 +10:00
|
|
|
return ErrSecret
|
2011-04-23 00:37:26 +10:00
|
|
|
}
|
2012-03-03 07:19:37 +11:00
|
|
|
out, mac, err = TsigGenerate(m, w.Client().TsigSecret[name], w.tsigRequestMAC, w.tsigTimersOnly)
|
2012-03-02 08:40:34 +11:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
w.tsigRequestMAC = mac
|
2012-03-03 07:19:37 +11:00
|
|
|
} else {
|
|
|
|
ok := false
|
|
|
|
out, ok = m.Pack()
|
|
|
|
if !ok {
|
|
|
|
return ErrPack
|
2011-11-03 09:06:54 +11:00
|
|
|
}
|
2011-04-16 07:55:27 +10:00
|
|
|
}
|
2012-05-05 07:18:29 +10:00
|
|
|
w.t = time.Now()
|
2012-03-03 07:19:37 +11:00
|
|
|
if _, err = w.writeClient(out); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2011-04-16 07:55:27 +10:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2011-11-03 09:06:54 +11:00
|
|
|
func (w *reply) writeClient(p []byte) (n int, err error) {
|
2012-05-26 18:24:47 +10:00
|
|
|
attempts := w.Client().Attempts
|
|
|
|
if attempts == 0 {
|
|
|
|
attempts = 1
|
2011-04-18 05:56:40 +10:00
|
|
|
}
|
2011-08-09 00:29:13 +10:00
|
|
|
if w.Client().Hijacked == nil {
|
2011-08-08 21:10:35 +10:00
|
|
|
if err = w.Dial(); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2011-04-16 07:55:27 +10:00
|
|
|
}
|
2011-08-04 21:49:40 +10:00
|
|
|
switch w.Client().Net {
|
2011-07-06 04:55:05 +10:00
|
|
|
case "tcp", "tcp4", "tcp6":
|
2011-04-16 07:55:27 +10:00
|
|
|
if len(p) < 2 {
|
|
|
|
return 0, io.ErrShortBuffer
|
|
|
|
}
|
2012-05-26 18:24:47 +10:00
|
|
|
for a := 0; a < attempts; a++ {
|
|
|
|
setTimeouts(w)
|
2011-08-09 21:15:25 +10:00
|
|
|
a, b := packUint16(uint16(len(p)))
|
|
|
|
n, err = w.conn.Write([]byte{a, b})
|
2011-04-16 07:55:27 +10:00
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
if n != 2 {
|
|
|
|
return n, io.ErrShortWrite
|
|
|
|
}
|
2011-08-08 21:10:35 +10:00
|
|
|
n, err = w.conn.Write(p)
|
2011-04-16 07:55:27 +10:00
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return n, err
|
|
|
|
}
|
|
|
|
i := n
|
|
|
|
if i < len(p) {
|
2011-08-08 21:10:35 +10:00
|
|
|
j, err := w.conn.Write(p[i:len(p)])
|
2011-04-16 07:55:27 +10:00
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
// We are half way in our write...
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
return i, err
|
|
|
|
}
|
|
|
|
i += j
|
|
|
|
}
|
|
|
|
n = i
|
|
|
|
}
|
2012-05-26 18:24:47 +10:00
|
|
|
case "", "udp", "udp4", "udp6":
|
|
|
|
for a := 0; a < attempts; a++ {
|
|
|
|
setTimeouts(w)
|
2012-01-27 18:39:41 +11:00
|
|
|
n, err = w.conn.(*net.UDPConn).Write(p)
|
2011-04-16 07:55:27 +10:00
|
|
|
if err != nil {
|
|
|
|
if e, ok := err.(net.Error); ok && e.Timeout() {
|
|
|
|
continue
|
|
|
|
}
|
2012-01-24 06:35:14 +11:00
|
|
|
return n, err
|
2011-04-16 07:55:27 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-24 06:35:14 +11:00
|
|
|
return
|
2011-04-16 07:55:27 +10:00
|
|
|
}
|
2012-05-05 07:18:29 +10:00
|
|
|
|
2012-05-26 18:24:47 +10:00
|
|
|
func setTimeouts(w *reply) {
|
|
|
|
if w.Client().ReadTimeout == 0 {
|
|
|
|
w.conn.SetReadDeadline(time.Now().Add(2 * 1e9))
|
|
|
|
} else {
|
|
|
|
w.conn.SetReadDeadline(time.Now().Add(w.Client().ReadTimeout))
|
|
|
|
}
|
|
|
|
|
|
|
|
if w.Client().WriteTimeout == 0 {
|
|
|
|
w.conn.SetWriteDeadline(time.Now().Add(2 * 1e9))
|
|
|
|
} else {
|
|
|
|
w.conn.SetWriteDeadline(time.Now().Add(w.Client().WriteTimeout))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-05 07:18:29 +10:00
|
|
|
// Close implents the RequestWriter.Close method
|
|
|
|
func (w *reply) Close() (err error) { return w.conn.Close() }
|
|
|
|
|
|
|
|
// Client returns a pointer to the client
|
|
|
|
func (w *reply) Client() *Client { return w.client }
|
|
|
|
|
|
|
|
// Request returns the request contained in reply
|
|
|
|
func (w *reply) Request() *Msg { return w.req }
|
|
|
|
|
|
|
|
// TsigStatus implements the RequestWriter.TsigStatus method
|
|
|
|
func (w *reply) TsigStatus() error { return w.tsigStatus }
|