A simple responder nameserver
This commit is contained in:
parent
c729cdd971
commit
e57dc24115
|
@ -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
1
msg.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue