208 lines
5.0 KiB
Go
208 lines
5.0 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.
|
|
//
|
|
// 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 */}
|
|
//
|
|
// su := new(Server) // create new sever
|
|
// su.Address = "127.0.0.1" // listen address
|
|
// su.Port = "8053" // listen port
|
|
// var us *myserv
|
|
// uch :=make(chan bool)
|
|
// go su.NewResponder(us, uch) // 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 {
|
|
cu *net.UDPConn // udp conn
|
|
ct *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 only used to stop the responder.
|
|
// Send 'true' to make it stop
|
|
func (res *Server) NewResponder(h Responder, ch chan bool) os.Error {
|
|
var port string
|
|
if len(res.Address) == 0 {
|
|
// We cannot start responding without an addresss
|
|
return nil
|
|
}
|
|
if res.Port == "" {
|
|
port = "53"
|
|
} else {
|
|
port = res.Port
|
|
}
|
|
switch res.Tcp {
|
|
case true:
|
|
tch := make(chan msg)
|
|
a, _ := net.ResolveTCPAddr(res.Address + ":" + port)
|
|
go listenerTCP(a, tch)
|
|
foreverTCP:
|
|
for {
|
|
select {
|
|
case <-ch:
|
|
ch <- true
|
|
/* stop listening */
|
|
break foreverTCP
|
|
case s := <-tch:
|
|
if s.err != nil {
|
|
//continue
|
|
}
|
|
go h.ResponderTCP(s.ct, s.msg)
|
|
}
|
|
}
|
|
|
|
case false:
|
|
uch := make(chan msg)
|
|
a, _ := net.ResolveUDPAddr(res.Address + ":" + port)
|
|
go listenerUDP(a, uch)
|
|
foreverUDP:
|
|
for {
|
|
select {
|
|
case <-ch:
|
|
ch <- true // last echo
|
|
break foreverUDP
|
|
case s := <-uch:
|
|
if s.err != nil {
|
|
println(s.err)
|
|
//continue?
|
|
} else {
|
|
go h.ResponderUDP(s.cu, s.addr, s.msg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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{cu: c, addr: radd, msg: m}
|
|
}
|
|
}
|
|
|
|
// Listen for TCP requests.
|
|
func listenerTCP(a *net.TCPAddr, ch chan msg) {
|
|
t, err := net.ListenTCP("tcp", a)
|
|
if err != nil {
|
|
ch <- msg{err: err}
|
|
return
|
|
}
|
|
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{ct: 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
|
|
}
|