dns/responder/responder.go
Miek Gieben 896df96f94 Responder channel is now os.Error
to make it possible to send errors back
2011-01-27 20:16:58 +01:00

281 lines
7.2 KiB
Go

// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// DNS server implementation
// Package responder implements a DNS server. Any nameserver needs to implement
// the Responder interface to get things going. Each incoming query is handled
// in a seperate goroutine.
//
// Typical usage of the package:
//
// type myserv Server
// func (s *myserv) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) { /* UDP reply */ }
// func (s *myserv) ResponderTCP(c *net.TCPConn, in []byte) { /* TCP reply */}
//
// s := new(Server) // create new sever
// s.Address = "127.0.0.1" // listen address
// s.Port = "8053" // listen port
// var m *myserv
// ch :=make(chan bool)
// go s.NewResponder(m, ch) // start the responder
package responder
import (
"os"
"net"
"dns"
)
// Options for a nameserver.
type Server struct {
Address string // interface to use, for multiple interfaces, use multiple servers
Port string // what port to use
Timeout int // seconds before giving up on packet
Tcp bool // use TCP
}
type msg struct {
udp *net.UDPConn // udp conn
tcp *net.TCPConn // tcp conn
addr net.Addr // remote address
msg []byte // raw dns message
err os.Error // any errors
}
// Every nameserver implements the Responder interface. It defines
// the kind of nameserver
type Responder interface {
// Receives the raw message content and writes back
// an UDP response. An UDP connection needs a remote
// address to write to. ResponderUDP() must take care of sending
// any response back to the requestor.
ResponderUDP(c *net.UDPConn, a net.Addr, in []byte)
// Receives the raw message content and writes back
// a TCP response. A TCP connection does need to
// know explicitly be told the remote address. ResponderTCP() must
// take care of sending back a response to the requestor.
ResponderTCP(c *net.TCPConn, in []byte)
}
// Start a new responder. The returned channel is used to stop the responder.
// Send 'nil' to make it stop. It can also return error via the channel.
func (res *Server) NewResponder(h Responder, stop chan os.Error) {
var port string
if len(res.Address) == 0 {
stop <- &dns.Error{Error: "No addresses"}
return
}
if res.Port == "" {
port = "53"
} else {
port = res.Port
}
switch res.Tcp {
case true:
tch := make(chan msg)
lch := make(chan *net.TCPListener)
a, _ := net.ResolveTCPAddr(res.Address + ":" + port)
go listenerTCP(a, tch, lch)
listener := <-lch
foreverTCP:
for {
select {
case <-stop:
stop <- nil
listener.Close()
break foreverTCP
case s := <-tch:
if s.err != nil {
stop <- s.err
} else {
go h.ResponderTCP(s.tcp, s.msg)
}
}
}
case false:
uch := make(chan msg)
a, _ := net.ResolveUDPAddr(res.Address + ":" + port)
go listenerUDP(a, uch)
foreverUDP:
for {
select {
case <-stop:
stop <- nil
break foreverUDP
case s := <-uch:
if s.err != nil {
stop <- s.err
} else {
go h.ResponderUDP(s.udp, s.addr, s.msg)
}
}
}
}
return
}
// Listen for UDP requests.
func listenerUDP(a *net.UDPAddr, ch chan msg) {
c, err := net.ListenUDP("udp", a)
if err != nil {
ch <- msg{err: err}
return
}
for {
m := make([]byte, dns.DefaultMsgSize) // TODO(mg) out of this loop?
n, radd, err := c.ReadFromUDP(m)
if err != nil {
ch <- msg{err: err}
continue
}
m = m[:n]
// if closed(ch) c.Close() TODO(mg)??
ch <- msg{udp: c, addr: radd, msg: m}
}
}
// Listen for TCP requests.
// How do I close this ?? TODO(mg)
func listenerTCP(a *net.TCPAddr, ch chan msg, listen chan *net.TCPListener) {
t, err := net.ListenTCP("tcp", a)
if err != nil {
listen <- nil
ch <- msg{err: err}
return
}
listen <- t // sent listener back (for closing it)
for {
l := make([]byte, 2) // receiver length
c, err := t.AcceptTCP()
if err != nil {
ch <- msg{err: err}
}
n, cerr := c.Read(l)
if cerr != nil {
ch <- msg{err: cerr}
}
length := uint16(l[0])<<8 | uint16(l[1])
if length == 0 {
// Send err mesg
//return nil, &dns.Error{Error: "received nil msg length", Server: c.RemoteAddr(
}
m := make([]byte, length)
n, cerr = c.Read(m)
if cerr != nil {
//send msg TODO(mg)
//return nil, cerr
}
i := n
if i < int(length) {
n, err = c.Read(m[i:])
if err != nil {
//send err
//return nil, err
}
i += n
}
ch <- msg{tcp: c, msg: m}
}
}
// Send a buffer on the TCP connection.
func SendTCP(m []byte, c *net.TCPConn) os.Error {
l := make([]byte, 2)
l[0] = byte(len(m) >> 8)
l[1] = byte(len(m))
// First we send the length
_, err := c.Write(l)
if err != nil {
return err
}
// And the the message
_, err = c.Write(m)
if err != nil {
return err
}
return nil
}
// Send a buffer to the remove address. Only here because
// of the symmetry with SendTCP().
func SendUDP(m []byte, c *net.UDPConn, a net.Addr) os.Error {
_, err := c.WriteTo(m, a)
if err != nil {
return err
}
return nil
}
/*
// Basic implementation of a reflector nameserver which responds
// to queries for A types and replies with the qname as the ownername
// and querier's IP as the rdata
type reflectServer Server
func (s *reflectServer) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) {
o, ok := makePkt(a, in)
if ok {
out, ok1 := o.Pack()
if ok1 {
SendUDP(out, c, a)
}
}
}
func (s *reflectServer) ResponderTCP(c *net.TCPConn, in []byte) {
o, ok := makePkt(c.RemoteAddr(), in)
if ok {
out, ok1 := o.Pack()
if ok1 {
SendTCP(out, c)
}
}
}
func makePkt(a net.Addr, i []byte) (*dns.Msg, bool) {
msg := new(dns.Msg)
if !msg.Unpack(i) {
return nil, false
}
if msg.MsgHdr.Response == true {
return nil, false
}
m := new(dns.Msg)
m.MsgHdr.Id = msg.MsgHdr.Id
m.MsgHdr.Authoritative = true
m.MsgHdr.Response = true
m.MsgHdr.Opcode = dns.OpcodeQuery
m.MsgHdr.Rcode = dns.RcodeSuccess
m.Question = make([]dns.Question, 1)
m.Question[0] = msg.Question[0]
if msg.Question[0].Qtype != dns.TypeA {
// wrong question
m.MsgHdr.Rcode = dns.RcodeFormatError
return m ,true
}
m.Answer = make([]dns.RR, 1)
r := new(dns.RR_A)
r.Hdr = dns.RR_Header{Name: msg.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
ip, _ := net.ResolveUDPAddr(a.String())
r.A = ip.IP.To4()
m.Answer[0] = r
return m, true
}
// A simple nameserver implementation. It reponds to queries for the A record and replies
// with the qname as the ownername and the rdata of the A record set to the senders address.
//
// Sample (udp) usage:
// stop := make(chan bool)
// s := new(Server)
// go s.NewResponder(Reflector, stop)
var Reflector *reflectServer
What point is there to Export this?
*/