Responder channel is now os.Error

to make it possible to send errors back
This commit is contained in:
Miek Gieben 2011-01-27 20:16:58 +01:00
parent 44c00e1b57
commit 896df96f94
5 changed files with 124 additions and 119 deletions

View File

@ -223,7 +223,7 @@ func main() {
s.Address = addr s.Address = addr
s.Port = port s.Port = port
var srv *server var srv *server
rs := make(chan bool) rs := make(chan os.Error)
go s.NewResponder(srv, rs) go s.NewResponder(srv, rs)
forever: forever:
@ -236,7 +236,7 @@ forever:
break forever break forever
} }
} }
rs <- true // shutdown responder rs <- nil // shutdown responder
<-rs // wait for confirmation <-rs // wait for confirmation
// And the resolvers // And the resolvers
for _, q := range qr { for _, q := range qr {

View File

@ -17,115 +17,118 @@
package main package main
import ( import (
"os"
"net" "net"
"strconv"
"dns" "dns"
"dns/responder" "strconv"
"runtime" "dns/responder"
"os/signal" "runtime"
"os/signal"
) )
type server responder.Server type server responder.Server
func reply(a net.Addr, in []byte, tcp bool) *dns.Msg { func reply(a net.Addr, in []byte, tcp bool) *dns.Msg {
inmsg := new(dns.Msg) inmsg := new(dns.Msg)
if !inmsg.Unpack(in) { if !inmsg.Unpack(in) {
println("Unpacking failed") println("Unpacking failed")
return nil return nil
} }
if inmsg.MsgHdr.Response == true { if inmsg.MsgHdr.Response == true {
return nil // Don't answer responses return nil // Don't answer responses
} }
m := new(dns.Msg) m := new(dns.Msg)
m.MsgHdr.Id = inmsg.MsgHdr.Id m.MsgHdr.Id = inmsg.MsgHdr.Id
m.MsgHdr.Authoritative = true m.MsgHdr.Authoritative = true
m.MsgHdr.Response = true m.MsgHdr.Response = true
m.MsgHdr.Opcode = dns.OpcodeQuery m.MsgHdr.Opcode = dns.OpcodeQuery
m.MsgHdr.Rcode = dns.RcodeSuccess m.MsgHdr.Rcode = dns.RcodeSuccess
m.Question = make([]dns.Question, 1) m.Question = make([]dns.Question, 1)
m.Answer = make([]dns.RR, 1) m.Answer = make([]dns.RR, 1)
m.Extra = make([]dns.RR, 1) m.Extra = make([]dns.RR, 1)
r := new(dns.RR_A) r := new(dns.RR_A)
r.Hdr = dns.RR_Header{Name: "whoami.miek.nl.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0} r.Hdr = dns.RR_Header{Name: "whoami.miek.nl.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
ip, _ := net.ResolveUDPAddr(a.String()) // No general variant for both upd and tcp ip, _ := net.ResolveUDPAddr(a.String()) // No general variant for both upd and tcp
r.A = ip.IP.To4() // To4 very important r.A = ip.IP.To4() // To4 very important
t := new(dns.RR_TXT) t := new(dns.RR_TXT)
t.Hdr = dns.RR_Header{Name: "whoami.miek.nl.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0} t.Hdr = dns.RR_Header{Name: "whoami.miek.nl.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}
if tcp { if tcp {
t.Txt = "Port: " + strconv.Itoa(ip.Port) + " (tcp)" t.Txt = "Port: " + strconv.Itoa(ip.Port) + " (tcp)"
} else { } else {
t.Txt = "Port: " + strconv.Itoa(ip.Port) + " (udp)" t.Txt = "Port: " + strconv.Itoa(ip.Port) + " (udp)"
} }
m.Question[0] = inmsg.Question[0] m.Question[0] = inmsg.Question[0]
m.Answer[0] = r m.Answer[0] = r
m.Extra[0] = t m.Extra[0] = t
return m return m
} }
func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) { func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) {
m := reply(a, in, false) m := reply(a, in, false)
if m == nil { if m == nil {
return return
} }
out, ok := m.Pack() out, ok := m.Pack()
if !ok { if !ok {
println("Failed to pack") println("Failed to pack")
return return
} }
responder.SendUDP(out, c, a) responder.SendUDP(out, c, a)
} }
func (s *server) ResponderTCP(c *net.TCPConn, in []byte) { func (s *server) ResponderTCP(c *net.TCPConn, in []byte) {
m := reply(c.RemoteAddr(), in, true) m := reply(c.RemoteAddr(), in, true)
if m == nil { if m == nil {
return return
} }
out, ok := m.Pack() out, ok := m.Pack()
if !ok { if !ok {
println("Failed to pack") println("Failed to pack")
return return
} }
responder.SendTCP(out, c) responder.SendTCP(out, c)
} }
func main() { func main() {
runtime.GOMAXPROCS(10) // Be bold runtime.GOMAXPROCS(10) // Be bold
s := new(responder.Server) s := new(responder.Server)
s.Address = "127.0.0.1" s.Address = "127.0.0.1"
s.Port = "8053" s.Port = "8053"
var srv *server var srv *server
ch := make(chan bool) ch := make(chan os.Error)
go s.NewResponder(srv, ch) go s.NewResponder(srv, ch)
t := new(responder.Server) t := new(responder.Server)
t.Address = "127.0.0.1" t.Address = "127.0.0.1"
t.Port = "8053" t.Port = "8053"
t.Tcp = true t.Tcp = true
var srvt *server var srvt *server
cht := make(chan bool) cht := make(chan os.Error)
go t.NewResponder(srvt, cht) go t.NewResponder(srvt, cht)
forever: forever:
for { for {
// Wait for a signal to stop // Wait for a signal to stop
select { select {
case <-signal.Incoming: case <-signal.Incoming:
println("Signal received, stopping") println("Signal received, stopping")
ch <- true ch <- nil
cht <- true cht <- nil
break forever break forever
case <-cht: case e := <-cht:
// last message from tcp channel // last message from tcp channel
case <-ch: println(e.String())
// last message from udp channel case e := <-ch:
} // last message from udp channel
} println(e.String())
close(cht) }
close(ch) }
close(cht)
close(ch)
} }

View File

@ -10,7 +10,8 @@
package main package main
import ( import (
"net" "os"
"net"
"dns" "dns"
"dns/responder" "dns/responder"
"os/signal" "os/signal"
@ -25,9 +26,9 @@ func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, in []byte) {
// NXdomain 'n stuff // NXdomain 'n stuff
println("Unpacking failed") println("Unpacking failed")
} }
if inmsg.MsgHdr.Response == true { if inmsg.MsgHdr.Response == true {
return // don't answer responses return // don't answer responses
} }
m := new(dns.Msg) m := new(dns.Msg)
m.MsgHdr.Id = inmsg.MsgHdr.Id m.MsgHdr.Id = inmsg.MsgHdr.Id
m.MsgHdr.Response = true m.MsgHdr.Response = true
@ -52,7 +53,7 @@ func main() {
s.Address = "127.0.0.1" s.Address = "127.0.0.1"
s.Port = "8053" s.Port = "8053"
var srv *server var srv *server
ch := make(chan bool) ch := make(chan os.Error)
go s.NewResponder(srv, ch) go s.NewResponder(srv, ch)
forever: forever:
@ -61,9 +62,13 @@ forever:
select { select {
case <-signal.Incoming: case <-signal.Incoming:
println("Signal received, stopping") println("Signal received, stopping")
ch <- true ch <- nil
<-ch <-ch
break forever break forever
case e := <-cht:
println(e.String())
case e := <-ch:
println(e.String())
} }
} }
} }

View File

@ -59,12 +59,12 @@ type Responder interface {
ResponderTCP(c *net.TCPConn, in []byte) ResponderTCP(c *net.TCPConn, in []byte)
} }
// Start a new responder. The returned channel is only used to stop the responder. // Start a new responder. The returned channel is used to stop the responder.
// Send 'true' to make it stop // Send 'nil' to make it stop. It can also return error via the channel.
func (res *Server) NewResponder(h Responder, stop chan bool) { func (res *Server) NewResponder(h Responder, stop chan os.Error) {
var port string var port string
if len(res.Address) == 0 { if len(res.Address) == 0 {
// We cannot start responding without an addresss stop <- &dns.Error{Error: "No addresses"}
return return
} }
if res.Port == "" { if res.Port == "" {
@ -83,14 +83,12 @@ func (res *Server) NewResponder(h Responder, stop chan bool) {
for { for {
select { select {
case <-stop: case <-stop:
stop <- true stop <- nil
listener.Close() listener.Close()
break foreverTCP break foreverTCP
case s := <-tch: case s := <-tch:
if s.err != nil { if s.err != nil {
// always fatal?? stop <- s.err
stop <- false
println(s.err.String())
} else { } else {
go h.ResponderTCP(s.tcp, s.msg) go h.ResponderTCP(s.tcp, s.msg)
} }
@ -105,13 +103,11 @@ func (res *Server) NewResponder(h Responder, stop chan bool) {
for { for {
select { select {
case <-stop: case <-stop:
stop <- true stop <- nil
break foreverUDP break foreverUDP
case s := <-uch: case s := <-uch:
if s.err != nil { if s.err != nil {
//continue stop <- s.err
stop <- false
println(s.err.String())
} else { } else {
go h.ResponderUDP(s.udp, s.addr, s.msg) go h.ResponderUDP(s.udp, s.addr, s.msg)
} }

View File

@ -1,6 +1,7 @@
package responder package responder
import ( import (
"os"
"testing" "testing"
"fmt" "fmt"
"dns" "dns"
@ -66,7 +67,7 @@ func TestResponder(t *testing.T) {
su.Address = "127.0.0.1" su.Address = "127.0.0.1"
su.Port = "8053" su.Port = "8053"
var us *myserv var us *myserv
uch := make(chan bool) uch := make(chan os.Error)
go su.NewResponder(us, uch) go su.NewResponder(us, uch)
/* tcp servertje */ /* tcp servertje */
@ -75,23 +76,23 @@ func TestResponder(t *testing.T) {
st.Port = "8053" st.Port = "8053"
st.Tcp = true st.Tcp = true
var ts *myserv var ts *myserv
tch := make(chan bool) tch := make(chan os.Error)
go st.NewResponder(ts, tch) go st.NewResponder(ts, tch)
time.Sleep(1 * 1e9) time.Sleep(1 * 1e9)
uch <- true uch <- nil
tch <- true tch <- nil
<-uch <-uch
<-tch <-tch
} }
/* /*
func TestReflectorResponder(t *testing.T) { func TestReflectorResponder(t *testing.T) {
stop := make(chan bool) stop := make(chan os.Error)
s := new(Server) s := new(Server)
s.Port = "8053" s.Port = "8053"
s.Address = "127.0.0.1" s.Address = "127.0.0.1"
stoptcp := make(chan bool) stoptcp := make(chan os.Error)
stcp := new(Server) stcp := new(Server)
stcp.Port = "8053" stcp.Port = "8053"
stcp.Address = "127.0.0.1" stcp.Address = "127.0.0.1"
@ -101,8 +102,8 @@ func TestReflectorResponder(t *testing.T) {
go s.NewResponder(Reflector, stop) go s.NewResponder(Reflector, stop)
time.Sleep(1 * 1e9) time.Sleep(1 * 1e9)
stop <- true stop <- nil
stoptcp <- true stoptcp <- nil
<-stop <-stop
<-stoptcp <-stoptcp
} }
@ -175,7 +176,7 @@ func TestResponderTsig(t *testing.T) {
su.Address = "127.0.0.1" su.Address = "127.0.0.1"
su.Port = "8053" su.Port = "8053"
var us *servtsig var us *servtsig
uch := make(chan bool) uch := make(chan os.Error)
go su.NewResponder(us, uch) go su.NewResponder(us, uch)
/* tcp servertje */ /* tcp servertje */
@ -184,11 +185,11 @@ func TestResponderTsig(t *testing.T) {
st.Port = "8053" st.Port = "8053"
st.Tcp = true st.Tcp = true
var ts *servtsig var ts *servtsig
tch := make(chan bool) tch := make(chan os.Error)
go st.NewResponder(ts, tch) go st.NewResponder(ts, tch)
time.Sleep(1 * 1e9) time.Sleep(1 * 1e9)
uch <- true uch <- nil
tch <- true tch <- nil
<-uch <-uch
<-tch <-tch
} }