123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- // DNS server implementation.
-
- package dns
-
- import (
- "context"
- "crypto/tls"
- "encoding/binary"
- "errors"
- "io"
- "net"
- "strings"
- "sync"
- "time"
- )
-
- // Default maximum number of TCP queries before we close the socket.
- const maxTCPQueries = 128
-
- // aLongTimeAgo is a non-zero time, far in the past, used for
- // immediate cancelation of network operations.
- var aLongTimeAgo = time.Unix(1, 0)
-
- // Handler is implemented by any value that implements ServeDNS.
- type Handler interface {
- ServeDNS(w ResponseWriter, r *Msg)
- }
-
- // The HandlerFunc type is an adapter to allow the use of
- // ordinary functions as DNS handlers. If f is a function
- // with the appropriate signature, HandlerFunc(f) is a
- // Handler object that calls f.
- type HandlerFunc func(ResponseWriter, *Msg)
-
- // ServeDNS calls f(w, r).
- func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
- f(w, r)
- }
-
- // A ResponseWriter interface is used by an DNS handler to
- // construct an DNS response.
- type ResponseWriter interface {
- // LocalAddr returns the net.Addr of the server
- LocalAddr() net.Addr
- // RemoteAddr returns the net.Addr of the client that sent the current request.
- RemoteAddr() net.Addr
- // WriteMsg writes a reply back to the client.
- WriteMsg(*Msg) error
- // Write writes a raw buffer back to the client.
- Write([]byte) (int, error)
- // Close closes the connection.
- Close() error
- // TsigStatus returns the status of the Tsig.
- TsigStatus() error
- // TsigTimersOnly sets the tsig timers only boolean.
- TsigTimersOnly(bool)
- // Hijack lets the caller take over the connection.
- // After a call to Hijack(), the DNS package will not do anything with the connection.
- Hijack()
- }
-
- // A ConnectionStater interface is used by a DNS Handler to access TLS connection state
- // when available.
- type ConnectionStater interface {
- ConnectionState() *tls.ConnectionState
- }
-
- type response struct {
- closed bool // connection has been closed
- hijacked bool // connection has been hijacked by handler
- tsigTimersOnly bool
- tsigStatus error
- tsigRequestMAC string
- tsigSecret map[string]string // the tsig secrets
- udp net.PacketConn // i/o connection if UDP was used
- tcp net.Conn // i/o connection if TCP was used
- udpSession *SessionUDP // oob data to get egress interface right
- pcSession net.Addr // address to use when writing to a generic net.PacketConn
- writer Writer // writer to output the raw DNS bits
- }
-
- // handleRefused returns a HandlerFunc that returns REFUSED for every request it gets.
- func handleRefused(w ResponseWriter, r *Msg) {
- m := new(Msg)
- m.SetRcode(r, RcodeRefused)
- w.WriteMsg(m)
- }
-
- // HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
- // Deprecated: This function is going away.
- func HandleFailed(w ResponseWriter, r *Msg) {
- m := new(Msg)
- m.SetRcode(r, RcodeServerFailure)
- // does not matter if this write fails
- w.WriteMsg(m)
- }
-
- // ListenAndServe Starts a server on address and network specified Invoke handler
- // for incoming queries.
- func ListenAndServe(addr string, network string, handler Handler) error {
- server := &Server{Addr: addr, Net: network, Handler: handler}
- return server.ListenAndServe()
- }
-
- // ListenAndServeTLS acts like http.ListenAndServeTLS, more information in
- // http://golang.org/pkg/net/http/#ListenAndServeTLS
- func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error {
- cert, err := tls.LoadX509KeyPair(certFile, keyFile)
- if err != nil {
- return err
- }
-
- config := tls.Config{
- Certificates: []tls.Certificate{cert},
- }
-
- server := &Server{
- Addr: addr,
- Net: "tcp-tls",
- TLSConfig: &config,
- Handler: handler,
- }
-
- return server.ListenAndServe()
- }
-
- // ActivateAndServe activates a server with a listener from systemd,
- // l and p should not both be non-nil.
- // If both l and p are not nil only p will be used.
- // Invoke handler for incoming queries.
- func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
- server := &Server{Listener: l, PacketConn: p, Handler: handler}
- return server.ActivateAndServe()
- }
-
- // Writer writes raw DNS messages; each call to Write should send an entire message.
- type Writer interface {
- io.Writer
- }
-
- // Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
- type Reader interface {
- // ReadTCP reads a raw message from a TCP connection. Implementations may alter
- // connection properties, for example the read-deadline.
- ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
- // ReadUDP reads a raw message from a UDP connection. Implementations may alter
- // connection properties, for example the read-deadline.
- ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
- }
-
- // PacketConnReader is an optional interface that Readers can implement to support using generic net.PacketConns.
- type PacketConnReader interface {
- Reader
-
- // ReadPacketConn reads a raw message from a generic net.PacketConn UDP connection. Implementations may
- // alter connection properties, for example the read-deadline.
- ReadPacketConn(conn net.PacketConn, timeout time.Duration) ([]byte, net.Addr, error)
- }
-
- // defaultReader is an adapter for the Server struct that implements the Reader and
- // PacketConnReader interfaces using the readTCP, readUDP and readPacketConn funcs
- // of the embedded Server.
- type defaultReader struct {
- *Server
- }
-
- var _ PacketConnReader = defaultReader{}
-
- func (dr defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
- return dr.readTCP(conn, timeout)
- }
-
- func (dr defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
- return dr.readUDP(conn, timeout)
- }
-
- func (dr defaultReader) ReadPacketConn(conn net.PacketConn, timeout time.Duration) ([]byte, net.Addr, error) {
- return dr.readPacketConn(conn, timeout)
- }
-
- // DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
- // Implementations should never return a nil Reader.
- // Readers should also implement the optional PacketConnReader interface.
- // PacketConnReader is required to use a generic net.PacketConn.
- type DecorateReader func(Reader) Reader
-
- // DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
- // Implementations should never return a nil Writer.
- type DecorateWriter func(Writer) Writer
-
- // A Server defines parameters for running an DNS server.
- type Server struct {
- // Address to listen on, ":dns" if empty.
- Addr string
- // if "tcp" or "tcp-tls" (DNS over TLS) it will invoke a TCP listener, otherwise an UDP one
- Net string
- // TCP Listener to use, this is to aid in systemd's socket activation.
- Listener net.Listener
- // TLS connection configuration
- TLSConfig *tls.Config
- // UDP "Listener" to use, this is to aid in systemd's socket activation.
- PacketConn net.PacketConn
- // Handler to invoke, dns.DefaultServeMux if nil.
- Handler Handler
- // Default buffer size to use to read incoming UDP messages. If not set
- // it defaults to MinMsgSize (512 B).
- UDPSize int
- // The net.Conn.SetReadTimeout value for new connections, defaults to 2 * time.Second.
- ReadTimeout time.Duration
- // The net.Conn.SetWriteTimeout value for new connections, defaults to 2 * time.Second.
- WriteTimeout time.Duration
- // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
- IdleTimeout func() time.Duration
- // Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
- TsigSecret map[string]string
- // If NotifyStartedFunc is set it is called once the server has started listening.
- NotifyStartedFunc func()
- // DecorateReader is optional, allows customization of the process that reads raw DNS messages.
- DecorateReader DecorateReader
- // DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
- DecorateWriter DecorateWriter
- // Maximum number of TCP queries before we close the socket. Default is maxTCPQueries (unlimited if -1).
- MaxTCPQueries int
- // Whether to set the SO_REUSEPORT socket option, allowing multiple listeners to be bound to a single address.
- // It is only supported on go1.11+ and when using ListenAndServe.
- ReusePort bool
- // AcceptMsgFunc will check the incoming message and will reject it early in the process.
- // By default DefaultMsgAcceptFunc will be used.
- MsgAcceptFunc MsgAcceptFunc
-
- // Shutdown handling
- lock sync.RWMutex
- started bool
- shutdown chan struct{}
- conns map[net.Conn]struct{}
-
- // A pool for UDP message buffers.
- udpPool sync.Pool
- }
-
- func (srv *Server) isStarted() bool {
- srv.lock.RLock()
- started := srv.started
- srv.lock.RUnlock()
- return started
- }
-
- func makeUDPBuffer(size int) func() interface{} {
- return func() interface{} {
- return make([]byte, size)
- }
- }
-
- func (srv *Server) init() {
- srv.shutdown = make(chan struct{})
- srv.conns = make(map[net.Conn]struct{})
-
- if srv.UDPSize == 0 {
- srv.UDPSize = MinMsgSize
- }
- if srv.MsgAcceptFunc == nil {
- srv.MsgAcceptFunc = DefaultMsgAcceptFunc
- }
- if srv.Handler == nil {
- srv.Handler = DefaultServeMux
- }
-
- srv.udpPool.New = makeUDPBuffer(srv.UDPSize)
- }
-
- func unlockOnce(l sync.Locker) func() {
- var once sync.Once
- return func() { once.Do(l.Unlock) }
- }
-
- // ListenAndServe starts a nameserver on the configured address in *Server.
- func (srv *Server) ListenAndServe() error {
- unlock := unlockOnce(&srv.lock)
- srv.lock.Lock()
- defer unlock()
-
- if srv.started {
- return &Error{err: "server already started"}
- }
-
- addr := srv.Addr
- if addr == "" {
- addr = ":domain"
- }
-
- srv.init()
-
- switch srv.Net {
- case "tcp", "tcp4", "tcp6":
- l, err := listenTCP(srv.Net, addr, srv.ReusePort)
- if err != nil {
- return err
- }
- srv.Listener = l
- srv.started = true
- unlock()
- return srv.serveTCP(l)
- case "tcp-tls", "tcp4-tls", "tcp6-tls":
- if srv.TLSConfig == nil || (len(srv.TLSConfig.Certificates) == 0 && srv.TLSConfig.GetCertificate == nil) {
- return errors.New("dns: neither Certificates nor GetCertificate set in Config")
- }
- network := strings.TrimSuffix(srv.Net, "-tls")
- l, err := listenTCP(network, addr, srv.ReusePort)
- if err != nil {
- return err
- }
- l = tls.NewListener(l, srv.TLSConfig)
- srv.Listener = l
- srv.started = true
- unlock()
- return srv.serveTCP(l)
- case "udp", "udp4", "udp6":
- l, err := listenUDP(srv.Net, addr, srv.ReusePort)
- if err != nil {
- return err
- }
- u := l.(*net.UDPConn)
- if e := setUDPSocketOptions(u); e != nil {
- u.Close()
- return e
- }
- srv.PacketConn = l
- srv.started = true
- unlock()
- return srv.serveUDP(u)
- }
- return &Error{err: "bad network"}
- }
-
- // ActivateAndServe starts a nameserver with the PacketConn or Listener
- // configured in *Server. Its main use is to start a server from systemd.
- func (srv *Server) ActivateAndServe() error {
- unlock := unlockOnce(&srv.lock)
- srv.lock.Lock()
- defer unlock()
-
- if srv.started {
- return &Error{err: "server already started"}
- }
-
- srv.init()
-
- if srv.PacketConn != nil {
- // Check PacketConn interface's type is valid and value
- // is not nil
- if t, ok := srv.PacketConn.(*net.UDPConn); ok && t != nil {
- if e := setUDPSocketOptions(t); e != nil {
- return e
- }
- }
- srv.started = true
- unlock()
- return srv.serveUDP(srv.PacketConn)
- }
- if srv.Listener != nil {
- srv.started = true
- unlock()
- return srv.serveTCP(srv.Listener)
- }
- return &Error{err: "bad listeners"}
- }
-
- // Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and
- // ActivateAndServe will return.
- func (srv *Server) Shutdown() error {
- return srv.ShutdownContext(context.Background())
- }
-
- // ShutdownContext shuts down a server. After a call to ShutdownContext,
- // ListenAndServe and ActivateAndServe will return.
- //
- // A context.Context may be passed to limit how long to wait for connections
- // to terminate.
- func (srv *Server) ShutdownContext(ctx context.Context) error {
- srv.lock.Lock()
- if !srv.started {
- srv.lock.Unlock()
- return &Error{err: "server not started"}
- }
-
- srv.started = false
-
- if srv.PacketConn != nil {
- srv.PacketConn.SetReadDeadline(aLongTimeAgo) // Unblock reads
- }
-
- if srv.Listener != nil {
- srv.Listener.Close()
- }
-
- for rw := range srv.conns {
- rw.SetReadDeadline(aLongTimeAgo) // Unblock reads
- }
-
- srv.lock.Unlock()
-
- if testShutdownNotify != nil {
- testShutdownNotify.Broadcast()
- }
-
- var ctxErr error
- select {
- case <-srv.shutdown:
- case <-ctx.Done():
- ctxErr = ctx.Err()
- }
-
- if srv.PacketConn != nil {
- srv.PacketConn.Close()
- }
-
- return ctxErr
- }
-
- var testShutdownNotify *sync.Cond
-
- // getReadTimeout is a helper func to use system timeout if server did not intend to change it.
- func (srv *Server) getReadTimeout() time.Duration {
- if srv.ReadTimeout != 0 {
- return srv.ReadTimeout
- }
- return dnsTimeout
- }
-
- // serveTCP starts a TCP listener for the server.
- func (srv *Server) serveTCP(l net.Listener) error {
- defer l.Close()
-
- if srv.NotifyStartedFunc != nil {
- srv.NotifyStartedFunc()
- }
-
- var wg sync.WaitGroup
- defer func() {
- wg.Wait()
- close(srv.shutdown)
- }()
-
- for srv.isStarted() {
- rw, err := l.Accept()
- if err != nil {
- if !srv.isStarted() {
- return nil
- }
- if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
- continue
- }
- return err
- }
- srv.lock.Lock()
- // Track the connection to allow unblocking reads on shutdown.
- srv.conns[rw] = struct{}{}
- srv.lock.Unlock()
- wg.Add(1)
- go srv.serveTCPConn(&wg, rw)
- }
-
- return nil
- }
-
- // serveUDP starts a UDP listener for the server.
- func (srv *Server) serveUDP(l net.PacketConn) error {
- defer l.Close()
-
- reader := Reader(defaultReader{srv})
- if srv.DecorateReader != nil {
- reader = srv.DecorateReader(reader)
- }
-
- lUDP, isUDP := l.(*net.UDPConn)
- readerPC, canPacketConn := reader.(PacketConnReader)
- if !isUDP && !canPacketConn {
- return &Error{err: "PacketConnReader was not implemented on Reader returned from DecorateReader but is required for net.PacketConn"}
- }
-
- if srv.NotifyStartedFunc != nil {
- srv.NotifyStartedFunc()
- }
-
- var wg sync.WaitGroup
- defer func() {
- wg.Wait()
- close(srv.shutdown)
- }()
-
- rtimeout := srv.getReadTimeout()
- // deadline is not used here
- for srv.isStarted() {
- var (
- m []byte
- sPC net.Addr
- sUDP *SessionUDP
- err error
- )
- if isUDP {
- m, sUDP, err = reader.ReadUDP(lUDP, rtimeout)
- } else {
- m, sPC, err = readerPC.ReadPacketConn(l, rtimeout)
- }
- if err != nil {
- if !srv.isStarted() {
- return nil
- }
- if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
- continue
- }
- return err
- }
- if len(m) < headerSize {
- if cap(m) == srv.UDPSize {
- srv.udpPool.Put(m[:srv.UDPSize])
- }
- continue
- }
- wg.Add(1)
- go srv.serveUDPPacket(&wg, m, l, sUDP, sPC)
- }
-
- return nil
- }
-
- // Serve a new TCP connection.
- func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
- w := &response{tsigSecret: srv.TsigSecret, tcp: rw}
- if srv.DecorateWriter != nil {
- w.writer = srv.DecorateWriter(w)
- } else {
- w.writer = w
- }
-
- reader := Reader(defaultReader{srv})
- if srv.DecorateReader != nil {
- reader = srv.DecorateReader(reader)
- }
-
- idleTimeout := tcpIdleTimeout
- if srv.IdleTimeout != nil {
- idleTimeout = srv.IdleTimeout()
- }
-
- timeout := srv.getReadTimeout()
-
- limit := srv.MaxTCPQueries
- if limit == 0 {
- limit = maxTCPQueries
- }
-
- for q := 0; (q < limit || limit == -1) && srv.isStarted(); q++ {
- m, err := reader.ReadTCP(w.tcp, timeout)
- if err != nil {
- // TODO(tmthrgd): handle error
- break
- }
- srv.serveDNS(m, w)
- if w.closed {
- break // Close() was called
- }
- if w.hijacked {
- break // client will call Close() themselves
- }
- // The first read uses the read timeout, the rest use the
- // idle timeout.
- timeout = idleTimeout
- }
-
- if !w.hijacked {
- w.Close()
- }
-
- srv.lock.Lock()
- delete(srv.conns, w.tcp)
- srv.lock.Unlock()
-
- wg.Done()
- }
-
- // Serve a new UDP request.
- func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u net.PacketConn, udpSession *SessionUDP, pcSession net.Addr) {
- w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: udpSession, pcSession: pcSession}
- if srv.DecorateWriter != nil {
- w.writer = srv.DecorateWriter(w)
- } else {
- w.writer = w
- }
-
- srv.serveDNS(m, w)
- wg.Done()
- }
-
- func (srv *Server) serveDNS(m []byte, w *response) {
- dh, off, err := unpackMsgHdr(m, 0)
- if err != nil {
- // Let client hang, they are sending crap; any reply can be used to amplify.
- return
- }
-
- req := new(Msg)
- req.setHdr(dh)
-
- switch action := srv.MsgAcceptFunc(dh); action {
- case MsgAccept:
- if req.unpack(dh, m, off) == nil {
- break
- }
-
- fallthrough
- case MsgReject, MsgRejectNotImplemented:
- opcode := req.Opcode
- req.SetRcodeFormatError(req)
- req.Zero = false
- if action == MsgRejectNotImplemented {
- req.Opcode = opcode
- req.Rcode = RcodeNotImplemented
- }
-
- // Are we allowed to delete any OPT records here?
- req.Ns, req.Answer, req.Extra = nil, nil, nil
-
- w.WriteMsg(req)
- fallthrough
- case MsgIgnore:
- if w.udp != nil && cap(m) == srv.UDPSize {
- srv.udpPool.Put(m[:srv.UDPSize])
- }
-
- return
- }
-
- w.tsigStatus = nil
- if w.tsigSecret != nil {
- if t := req.IsTsig(); t != nil {
- if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
- w.tsigStatus = TsigVerify(m, secret, "", false)
- } else {
- w.tsigStatus = ErrSecret
- }
- w.tsigTimersOnly = false
- w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
- }
- }
-
- if w.udp != nil && cap(m) == srv.UDPSize {
- srv.udpPool.Put(m[:srv.UDPSize])
- }
-
- srv.Handler.ServeDNS(w, req) // Writes back to the client
- }
-
- func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
- // If we race with ShutdownContext, the read deadline may
- // have been set in the distant past to unblock the read
- // below. We must not override it, otherwise we may block
- // ShutdownContext.
- srv.lock.RLock()
- if srv.started {
- conn.SetReadDeadline(time.Now().Add(timeout))
- }
- srv.lock.RUnlock()
-
- var length uint16
- if err := binary.Read(conn, binary.BigEndian, &length); err != nil {
- return nil, err
- }
-
- m := make([]byte, length)
- if _, err := io.ReadFull(conn, m); err != nil {
- return nil, err
- }
-
- return m, nil
- }
-
- func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
- srv.lock.RLock()
- if srv.started {
- // See the comment in readTCP above.
- conn.SetReadDeadline(time.Now().Add(timeout))
- }
- srv.lock.RUnlock()
-
- m := srv.udpPool.Get().([]byte)
- n, s, err := ReadFromSessionUDP(conn, m)
- if err != nil {
- srv.udpPool.Put(m)
- return nil, nil, err
- }
- m = m[:n]
- return m, s, nil
- }
-
- func (srv *Server) readPacketConn(conn net.PacketConn, timeout time.Duration) ([]byte, net.Addr, error) {
- srv.lock.RLock()
- if srv.started {
- // See the comment in readTCP above.
- conn.SetReadDeadline(time.Now().Add(timeout))
- }
- srv.lock.RUnlock()
-
- m := srv.udpPool.Get().([]byte)
- n, addr, err := conn.ReadFrom(m)
- if err != nil {
- srv.udpPool.Put(m)
- return nil, nil, err
- }
- m = m[:n]
- return m, addr, nil
- }
-
- // WriteMsg implements the ResponseWriter.WriteMsg method.
- func (w *response) WriteMsg(m *Msg) (err error) {
- if w.closed {
- return &Error{err: "WriteMsg called after Close"}
- }
-
- var data []byte
- if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
- if t := m.IsTsig(); t != nil {
- data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
- if err != nil {
- return err
- }
- _, err = w.writer.Write(data)
- return err
- }
- }
- data, err = m.Pack()
- if err != nil {
- return err
- }
- _, err = w.writer.Write(data)
- return err
- }
-
- // Write implements the ResponseWriter.Write method.
- func (w *response) Write(m []byte) (int, error) {
- if w.closed {
- return 0, &Error{err: "Write called after Close"}
- }
-
- switch {
- case w.udp != nil:
- if u, ok := w.udp.(*net.UDPConn); ok {
- return WriteToSessionUDP(u, m, w.udpSession)
- }
- return w.udp.WriteTo(m, w.pcSession)
- case w.tcp != nil:
- if len(m) > MaxMsgSize {
- return 0, &Error{err: "message too large"}
- }
-
- msg := make([]byte, 2+len(m))
- binary.BigEndian.PutUint16(msg, uint16(len(m)))
- copy(msg[2:], m)
- return w.tcp.Write(msg)
- default:
- panic("dns: internal error: udp and tcp both nil")
- }
- }
-
- // LocalAddr implements the ResponseWriter.LocalAddr method.
- func (w *response) LocalAddr() net.Addr {
- switch {
- case w.udp != nil:
- return w.udp.LocalAddr()
- case w.tcp != nil:
- return w.tcp.LocalAddr()
- default:
- panic("dns: internal error: udp and tcp both nil")
- }
- }
-
- // RemoteAddr implements the ResponseWriter.RemoteAddr method.
- func (w *response) RemoteAddr() net.Addr {
- switch {
- case w.udpSession != nil:
- return w.udpSession.RemoteAddr()
- case w.pcSession != nil:
- return w.pcSession
- case w.tcp != nil:
- return w.tcp.RemoteAddr()
- default:
- panic("dns: internal error: udpSession, pcSession and tcp are all nil")
- }
- }
-
- // TsigStatus implements the ResponseWriter.TsigStatus method.
- func (w *response) TsigStatus() error { return w.tsigStatus }
-
- // TsigTimersOnly implements the ResponseWriter.TsigTimersOnly method.
- func (w *response) TsigTimersOnly(b bool) { w.tsigTimersOnly = b }
-
- // Hijack implements the ResponseWriter.Hijack method.
- func (w *response) Hijack() { w.hijacked = true }
-
- // Close implements the ResponseWriter.Close method
- func (w *response) Close() error {
- if w.closed {
- return &Error{err: "connection already closed"}
- }
- w.closed = true
-
- switch {
- case w.udp != nil:
- // Can't close the udp conn, as that is actually the listener.
- return nil
- case w.tcp != nil:
- return w.tcp.Close()
- default:
- panic("dns: internal error: udp and tcp both nil")
- }
- }
-
- // ConnectionState() implements the ConnectionStater.ConnectionState() interface.
- func (w *response) ConnectionState() *tls.ConnectionState {
- type tlsConnectionStater interface {
- ConnectionState() tls.ConnectionState
- }
- if v, ok := w.tcp.(tlsConnectionStater); ok {
- t := v.ConnectionState()
- return &t
- }
- return nil
- }
|