From e57dc2411590735fdf6cad3e3fa7e49d08b21dd1 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Mon, 17 Jan 2011 15:43:54 +0100 Subject: [PATCH] A simple responder nameserver --- _examples/Makefile | 2 + msg.go | 1 + responder/reflector-responder.go | 120 ------------------------------- responder/responder.go | 34 ++++++--- responder/responder_test.go | 88 +++++++++++------------ 5 files changed, 70 insertions(+), 175 deletions(-) delete mode 100644 responder/reflector-responder.go diff --git a/_examples/Makefile b/_examples/Makefile index 5cc99b9b..04fb9615 100644 --- a/_examples/Makefile +++ b/_examples/Makefile @@ -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 diff --git a/msg.go b/msg.go index a7026f85..1673f337 100644 --- a/msg.go +++ b/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 } diff --git a/responder/reflector-responder.go b/responder/reflector-responder.go deleted file mode 100644 index 4a3b933d..00000000 --- a/responder/reflector-responder.go +++ /dev/null @@ -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 - -*/ - -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) { -} diff --git a/responder/responder.go b/responder/responder.go index d241dbf9..eae65d47 100644 --- a/responder/responder.go +++ b/responder/responder.go @@ -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 { diff --git a/responder/responder_test.go b/responder/responder_test.go index 95abbae7..ad8d8722 100644 --- a/responder/responder_test.go +++ b/responder/responder_test.go @@ -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) }