A simple responder nameserver

This commit is contained in:
Miek Gieben 2011-01-17 15:43:54 +01:00
parent c729cdd971
commit e57dc24115
5 changed files with 70 additions and 175 deletions

View File

@ -4,6 +4,7 @@ all:
gomake -C chaos
gomake -C axfr
gomake -C notify
gomake -C reflect
clean:
gomake -C mx clean
@ -11,3 +12,4 @@ clean:
gomake -C chaos clean
gomake -C axfr clean
gomake -C notify clean
gomake -C reflect clean

1
msg.go
View File

@ -273,6 +273,7 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
off += len(data)
}
case "A":
// It must be a slice of 4
if fv.Len() > net.IPv4len || off+fv.Len() > len(msg) {
return len(msg), false
}

View File

@ -1,120 +0,0 @@
/* A name server which sends back the IP address of its client, the
recursive resolver. When queried for type TXT, it sends back the text
form of the address. When queried for type A (resp. AAAA), it sends
back the IPv4 (resp. v6) address.
Similar services: whoami.ultradns.net, whoami.akamai.net. Also (but it
is not their normal goal): rs.dns-oarc.net, porttest.dns-oarc.net,
amiopen.openresolvers.org.
Stephane Bortzmeyer <stephane+grong@bortzmeyer.org>
*/
package responder
import (
"net"
"reflect"
"./types"
)
// Compile-time options
const includesPort = false // If false, sends only the address for TXT queries.
// If true, includes the UDP or TCP port.
// TODO: allow to secify the Qname it must respond to
func txtRecord(client net.Addr) []byte {
sclient := client.String()
if !includesPort {
tcpAddr, _ := net.ResolveTCPAddr(sclient)
sclient = tcpAddr.IP.String()
}
return types.ToTXT(sclient)
}
func txtSection(qname string, client net.Addr) (result types.RR) {
result.Name = qname
result.Type = types.TXT
result.Class = types.IN
result.TTL = 0
result.Data = txtRecord(client)
return
}
func addressSection(qname string, client net.IP) (result types.RR) {
result.Name = qname
result.Type = types.A
result.Class = types.IN
result.TTL = 0
result.Data = client
return
}
func aaaaSection(qname string, client net.IP) (result types.RR) {
result.Name = qname
result.Type = types.AAAA
result.Class = types.IN
result.TTL = 0
result.Data = client
return
}
func Respond(query types.DNSquery, config map[string]interface{}) types.DNSresponse {
var (
result types.DNSresponse
)
result.Ansection = nil
tcpAddr, _ := net.ResolveTCPAddr(query.Client.String())
ipaddressV4 := tcpAddr.IP.To4()
zonei, zoneset := config["zonename"]
zone := ""
if zoneset {
zone = reflect.NewValue(zonei).(*reflect.StringValue).Get()
}
switch {
case query.Qclass != types.IN:
result.Responsecode = types.SERVFAIL
case zone != "" && query.Qname != zone:
result.Responsecode = types.SERVFAIL
case query.Qtype == types.A:
result.Responsecode = types.NOERROR
if ipaddressV4 != nil {
ancount := 1
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = addressSection(query.Qname, ipaddressV4)
} else {
// ancount := 0
}
case query.Qtype == types.AAAA:
result.Responsecode = types.NOERROR
if ipaddressV4 == nil {
ancount := 1
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = aaaaSection(query.Qname, tcpAddr.IP)
} else {
// ancount := 0
}
case query.Qtype == types.TXT:
result.Responsecode = types.NOERROR
ancount := 1
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = txtSection(query.Qname, query.Client)
case query.Qtype == types.ALL:
result.Responsecode = types.NOERROR
ancount := 2
result.Ansection = make([]types.RR, ancount)
result.Ansection[0] = txtSection(query.Qname, query.Client)
if ipaddressV4 == nil {
result.Ansection[1] = aaaaSection(query.Qname, tcpAddr.IP)
} else {
result.Ansection[1] = addressSection(query.Qname, ipaddressV4)
}
default:
result.Responsecode = types.NOERROR
}
return result
}
func Init(firstoption int) {
}

View File

@ -98,9 +98,11 @@ func (res *Server) NewResponder(h Responder, ch chan bool) os.Error {
break foreverUDP
case s := <-uch:
if s.err != nil {
//continue
}
go h.ResponderUDP(s.cu, s.addr, s.msg)
println(s.err)
//continue?
} else {
go h.ResponderUDP(s.cu, s.addr, s.msg)
}
}
}
}
@ -108,30 +110,40 @@ func (res *Server) NewResponder(h Responder, ch chan bool) os.Error {
}
func listenerUDP(a *net.UDPAddr, ch chan msg) {
c, _ := net.ListenUDP("udp", a)
// check error TODO(mg)
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 {
// hmm
ch <- msg{err: err}
continue
}
m = m[:n]
// if closed(ch) c.Close() TODO(mg)
// if closed(ch) c.Close() TODO(mg)??
ch <- msg{cu: c, addr: radd, msg: m}
}
}
func listenerTCP(a *net.TCPAddr, ch chan msg) {
t, _ := net.ListenTCP("tcp", a)
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()
var _ = err // handle err TODO(mg)
if err != nil {
ch <- msg{err: err}
}
n, cerr := c.Read(l)
if err != nil {
// Send err mesg
if cerr != nil {
ch <- msg{err: cerr}
}
length := uint16(l[0])<<8 | uint16(l[1])
if length == 0 {

View File

@ -2,68 +2,68 @@ package responder
import (
"testing"
"dns"
"net"
"time"
"dns"
"net"
"time"
)
type myserv Server
func createpkg(id uint16, tcp bool, remove net.Addr) []byte {
m := new(dns.Msg)
m.MsgHdr.Id = id
m.MsgHdr.Authoritative = true
m.MsgHdr.AuthenticatedData = false
m.MsgHdr.RecursionAvailable = true
m.MsgHdr.Response = true
m.MsgHdr.Opcode = dns.OpcodeQuery
m.MsgHdr.Rcode = dns.RcodeSuccess
m.Question = make([]dns.Question, 1)
m.Question[0] = dns.Question{"miek.nl.", dns.TypeTXT, dns.ClassINET}
m.Answer = make([]dns.RR, 1)
t := new(dns.RR_TXT)
t.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 3600}
if tcp {
t.Txt = "Dit is iets anders TCP"
} else {
t.Txt = "Dit is iets anders UDP"
}
m.Answer[0] = t
out, _ := m.Pack()
return out
m := new(dns.Msg)
m.MsgHdr.Id = id
m.MsgHdr.Authoritative = true
m.MsgHdr.AuthenticatedData = false
m.MsgHdr.RecursionAvailable = true
m.MsgHdr.Response = true
m.MsgHdr.Opcode = dns.OpcodeQuery
m.MsgHdr.Rcode = dns.RcodeSuccess
m.Question = make([]dns.Question, 1)
m.Question[0] = dns.Question{"miek.nl.", dns.TypeTXT, dns.ClassINET}
m.Answer = make([]dns.RR, 1)
t := new(dns.RR_TXT)
t.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 3600}
if tcp {
t.Txt = "Dit is iets anders TCP"
} else {
t.Txt = "Dit is iets anders UDP"
}
m.Answer[0] = t
out, _ := m.Pack()
return out
}
func (s *myserv) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) {
inmsg := new(dns.Msg)
inmsg.Unpack(in)
out := createpkg(inmsg.MsgHdr.Id, false, a)
SendUDP(out, c, a)
inmsg := new(dns.Msg)
inmsg.Unpack(in)
out := createpkg(inmsg.MsgHdr.Id, false, a)
SendUDP(out, c, a)
}
func (s *myserv) ResponderTCP(c *net.TCPConn, in []byte) {
inmsg := new(dns.Msg)
inmsg.Unpack(in)
out := createpkg(inmsg.MsgHdr.Id, true, c.RemoteAddr())
SendTCP(out, c)
inmsg := new(dns.Msg)
inmsg.Unpack(in)
out := createpkg(inmsg.MsgHdr.Id, true, c.RemoteAddr())
SendTCP(out, c)
}
func TestResponder(t *testing.T) {
/* udp servertje */
/* udp servertje */
su := new(Server)
su.Address = "127.0.0.1"
su.Port = "8053"
var us *myserv
uch :=make(chan bool)
go su.NewResponder(us, uch)
su.Port = "8053"
var us *myserv
uch := make(chan bool)
go su.NewResponder(us, uch)
/* tcp servertje */
/* tcp servertje */
st := new(Server)
st.Address = "127.0.0.1"
st.Port = "8053"
st.Tcp = true
var ts *myserv
tch :=make(chan bool)
go st.NewResponder(ts, tch)
st.Port = "8053"
st.Tcp = true
var ts *myserv
tch := make(chan bool)
go st.NewResponder(ts, tch)
time.Sleep(100 * 1e9)
time.Sleep(100 * 1e9)
}