diff --git a/README.markdown b/README.markdown index 9727bc37..3701136f 100644 --- a/README.markdown +++ b/README.markdown @@ -5,8 +5,8 @@ supported. DNSSEC types too. EDNS0 is (see edns.go), UDP/TCP queries, TSIG, AXFR (and IXFR probably) too. Both client and server side programming is supported. -Sample programs can be found in the _examples directory. They can -be build with: make examples (after the dns package has been installed) +Sample programs can be found in the `_examples` directory. They can +be build with: `make examples` (after the dns package has been installed) The major omission at the moment is parsing Resource Records from strings. (i.e. supporting the RFC 1035 zone file format). @@ -15,9 +15,10 @@ Also the IPv6 support needs to be tested Everything else should be present and working. If not, drop me an email. Have fun! + Miek Gieben - 2010, 2011 - miek@miek.nl -Supported RFCs and features include: +## Supported RFCs and features include: * 1034/1035 - DNS standard * 1982 - Serial Arithmetic @@ -37,11 +38,12 @@ Supported RFCs and features include: * 4255 - SSHFP * 4408 - SPF * 5001 - NSID -* 5155 - NSEC -- todo +* 5155 - NSEC * 5936 - AXFR -Loosely based upon: -* ldns -* NSD -* Net::DNS -* GRONG +## Loosely based upon: + +* `ldns` +* `NSD` +* `Net::DNS` +* `GRONG` diff --git a/_examples/funkensturm/config.go b/_examples/funkensturm/config.go index a5e32328..81e1e1ee 100644 --- a/_examples/funkensturm/config.go +++ b/_examples/funkensturm/config.go @@ -2,7 +2,6 @@ package main import ( "dns" - "dns/resolver" ) func match(m *dns.Msg, d int) (*dns.Msg, bool) { @@ -26,17 +25,15 @@ func match(m *dns.Msg, d int) (*dns.Msg, bool) { return m, true } -func send(m *dns.Msg, ok bool) *dns.Msg { +func send(m *dns.Msg, ok bool) (out *dns.Msg) { switch ok { case true, false: - var in resolver.Msg for _, r := range qr { - r <- resolver.Msg{m, nil, nil} - in = <-r + out, _ = r.Query(m) } - return in.Dns // return the last + return } - return nil + return } // Return the configration diff --git a/_examples/funkensturm/config_delay.go b/_examples/funkensturm/config_delay.go index 76e97ec1..c7226d3b 100644 --- a/_examples/funkensturm/config_delay.go +++ b/_examples/funkensturm/config_delay.go @@ -7,7 +7,6 @@ import ( "dns" "fmt" "time" - "dns/resolver" ) const NSECDELAY = 1 * 1e9 // 1 second, meaning 1 qps (smaller means higher qps) @@ -47,7 +46,7 @@ func match(m *dns.Msg, d int) (*dns.Msg, bool) { return m, ok } -func delay(m *dns.Msg, ok bool) *dns.Msg { +func delay(m *dns.Msg, ok bool) (out *dns.Msg) { var ok1 bool switch ok { case true: @@ -55,26 +54,21 @@ func delay(m *dns.Msg, ok bool) *dns.Msg { if !ok1 { fmt.Fprintf(os.Stderr, "Info: Dropping: too often\n") time.Sleep(NSECDELAY) - return nil + return } else { fmt.Fprintf(os.Stderr, "Info: Ok: let it through\n") - var in resolver.Msg for _, r := range qr { - r <- resolver.Msg{m, nil, nil} - in = <-r + out, _ = r.Query(m) } - return in.Dns + return } case false: - var in resolver.Msg for _, r := range qr { - r <- resolver.Msg{m, nil, nil} - in = <-r + out, _ = r.Query(m) } - return in.Dns - return in.Dns + return } - return nil + return } // Return the configration diff --git a/_examples/funkensturm/config_proxy.go b/_examples/funkensturm/config_proxy.go index 84af40ac..81e1e1ee 100644 --- a/_examples/funkensturm/config_proxy.go +++ b/_examples/funkensturm/config_proxy.go @@ -2,7 +2,6 @@ package main import ( "dns" - "dns/resolver" ) func match(m *dns.Msg, d int) (*dns.Msg, bool) { @@ -26,17 +25,15 @@ func match(m *dns.Msg, d int) (*dns.Msg, bool) { return m, true } -func send(m *dns.Msg, ok bool) *dns.Msg { +func send(m *dns.Msg, ok bool) (out *dns.Msg) { switch ok { case true, false: - var in resolver.Msg for _, r := range qr { - r <- resolver.Msg{m, nil, nil} - in = <-r + out, _ = r.Query(m) } - return in.Dns + return } - return nil + return } // Return the configration diff --git a/_examples/funkensturm/config_sign.go b/_examples/funkensturm/config_sign.go index af63871e..7009ad9b 100644 --- a/_examples/funkensturm/config_sign.go +++ b/_examples/funkensturm/config_sign.go @@ -7,7 +7,6 @@ package main // We could also use one 1 key for multiple domains. import ( "dns" - "dns/resolver" "crypto/rsa" ) @@ -59,17 +58,15 @@ func match(m *dns.Msg, d int) (*dns.Msg, bool) { return m, true } -func send(m *dns.Msg, ok bool) *dns.Msg { +func send(m *dns.Msg, ok bool) (out *dns.Msg) { switch ok { case true, false: - var in resolver.Msg for _, r := range qr { - r <- resolver.Msg{m, nil, nil} - in = <-r + out, _ = r.Query(m) } - return in.Dns // return the last + return } - return nil + return } var pubkey *dns.RR_DNSKEY diff --git a/_examples/funkensturm/funkensturm.go b/_examples/funkensturm/funkensturm.go index c852b3bd..256d57dd 100644 --- a/_examples/funkensturm/funkensturm.go +++ b/_examples/funkensturm/funkensturm.go @@ -21,7 +21,7 @@ import ( type server dns.Server // Define a slice of channels for the resolver for sending the queries somewhere else. -var qr []chan resolver.Msg +var qr []*dns.Resolver // The configuration of Funkensturm var f *Funkensturm @@ -151,7 +151,7 @@ func doFunkensturm(i []byte) ([]byte, os.Error) { return out, nil } -func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, i []byte) { +func (s *server) ReplyUDP(c *net.UDPConn, a net.Addr, i []byte) { out, err := doFunkensturm(i) if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err.String()) @@ -159,12 +159,12 @@ func (s *server) ResponderUDP(c *net.UDPConn, a net.Addr, i []byte) { } if out != nil { - responder.SendUDP(out, c, a) + dns.SendUDP(out, c, a) } // nothing is send back } -func (s *server) ResponderTCP(c *net.TCPConn, i []byte) { +func (s *server) ReplyTCP(c *net.TCPConn, a net.Addr, i []byte) { out, err := doFunkensturm(i) if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err.String()) @@ -172,7 +172,7 @@ func (s *server) ResponderTCP(c *net.TCPConn, i []byte) { } if out != nil { - responder.SendTCP(out, c) + dns.SendTCP(out, c, a) } // nothing is send back } @@ -180,10 +180,10 @@ func (s *server) ResponderTCP(c *net.TCPConn, i []byte) { // split 127.0.0.1:53 into components // TODO IPv6 func splitAddrPort(s string) (a, p string) { - items := strings.Split(s, ":", 2) - a = items[0] - p = items[1] - return + items := strings.Split(s, ":", 2) + a = items[0] + p = items[1] + return } func main() { @@ -197,15 +197,13 @@ func main() { flag.Parse() resolvers := strings.Split(*rserver, ",", -1) - qr = make([]chan resolver.Msg, len(resolvers)) + qr = make([]*dns.Resolver, len(resolvers)) for i, ra := range resolvers { addr, port := splitAddrPort(ra) - // TODO error checking - // The resolver(s) - r := new(resolver.Resolver) + r := new(dns.Resolver) r.Servers = []string{addr} r.Port = port - qr[i] = r.NewQuerier() // connect to global qr[i + qr[i] = r } f = funkensturm() @@ -215,14 +213,10 @@ func main() { return } - // The responder - addr, port := splitAddrPort(*sserver) - s := new(responder.Server) - s.Address = addr - s.Port = port + // The server var srv *server - rs := make(chan os.Error) - go s.NewResponder(srv, rs) + quit := make(chan bool) + go dns.ListenAndServe(*sserver, srv, quit) forever: for { @@ -230,15 +224,9 @@ forever: select { case <-signal.Incoming: println("Signal received, stopping") - rs <- nil // shutdown responder + quit <- true break forever } } - close(rs) - - // And the resolvers - for _, q := range qr { - q <- resolver.Msg{} - <-q - } + close(quit) } diff --git a/resolver.go b/resolver.go index e9ce3cf3..99c23dfb 100644 --- a/resolver.go +++ b/resolver.go @@ -42,7 +42,7 @@ type Resolver struct { Rotate bool // round robin among servers -- TODO Tcp bool // use TCP Mangle func([]byte) []byte // mangle the packet - // rtt map[string]int server->int, smaller is faster 0, -1 is unreacheble + // rtt map[string]int server->int, smaller is faster 0, -1 is unreacheble } // Send a query using *res, q holds the question to be asked. @@ -50,136 +50,136 @@ type Resolver struct { func (res *Resolver) Query(q *Msg) (d *Msg, err os.Error) { var ( c net.Conn - in *Msg + in *Msg port string ) - if len(res.Servers) == 0 { - return nil, &Error{Error: "No servers defined"} - } + if len(res.Servers) == 0 { + return nil, &Error{Error: "No servers defined"} + } // len(res.Server) == 0 can be perfectly valid, when setting up the resolver - // It is now + // It is now if res.Port == "" { port = "53" } else { port = res.Port } - if q.Id == 0 { - // No Id sed, set it - q.SetId() - } - sending, ok := q.Pack() - if !ok { - return nil, &Error{Error: packErr} - } + if q.Id == 0 { + // No Id sed, set it + q.SetId() + } + sending, ok := q.Pack() + if !ok { + return nil, &Error{Error: packErr} + } - for i := 0; i < len(res.Servers); i++ { - server := res.Servers[i] + ":" + port - if res.Tcp { - c, err = net.Dial("tcp", "", server) - } else { - c, err = net.Dial("udp", "", server) - } - if err != nil { - continue - } - if res.Tcp { - in, err = exchangeTCP(c, sending, res, true) - } else { - in, err = exchangeUDP(c, sending, res, true) - } + for i := 0; i < len(res.Servers); i++ { + server := res.Servers[i] + ":" + port + if res.Tcp { + c, err = net.Dial("tcp", "", server) + } else { + c, err = net.Dial("udp", "", server) + } + if err != nil { + continue + } + if res.Tcp { + in, err = exchangeTCP(c, sending, res, true) + } else { + in, err = exchangeUDP(c, sending, res, true) + } - // Check id in.id != out.id, should be checked in the client! - c.Close() - if err != nil { - continue - } - break - } - if err != nil { - return nil, err - } - return in, nil + // Check id in.id != out.id, should be checked in the client! + c.Close() + if err != nil { + continue + } + break + } + if err != nil { + return nil, err + } + return in, nil } // q holds the inital query // channel is closed by AXfr func (res *Resolver) Axfr(q *Msg, m chan *Msg) { var port string - var err os.Error - var in *Msg + var err os.Error + var in *Msg if res.Port == "" { port = "53" } else { port = res.Port } - var _ = err // TODO(mg) + var _ = err // TODO(mg) - if q.Id == 0 { - q.SetId() - } - - sending, ok := q.Pack() - if !ok { - m <- nil - return + if q.Id == 0 { + q.SetId() } - SERVER: - for i := 0; i < len(res.Servers); i++ { - server := res.Servers[i] + ":" + port - c, cerr := net.Dial("tcp", "", server) - if cerr != nil { - err = cerr - continue SERVER - } - first := true - // Start the AXFR - for { - if first { - in, cerr = exchangeTCP(c, sending, res, true) - } else { - in, err = exchangeTCP(c, sending, res, false) - } + sending, ok := q.Pack() + if !ok { + m <- nil + return + } - if cerr != nil { - // Failed to send, try the next - err = cerr - c.Close() - continue SERVER - } - if in.Id != q.Id { - m <- nil - return - } +SERVER: + for i := 0; i < len(res.Servers); i++ { + server := res.Servers[i] + ":" + port + c, cerr := net.Dial("tcp", "", server) + if cerr != nil { + err = cerr + continue SERVER + } + first := true + // Start the AXFR + for { + if first { + in, cerr = exchangeTCP(c, sending, res, true) + } else { + in, err = exchangeTCP(c, sending, res, false) + } - if first { - if !checkSOA(in, true) { - c.Close() - continue SERVER - } - m <- in - first = !first - } + if cerr != nil { + // Failed to send, try the next + err = cerr + c.Close() + continue SERVER + } + if in.Id != q.Id { + m <- nil + return + } - if !first { - if !checkSOA(in, false) { - // Soa record not the last one - m <- in - continue - } else { - c.Close() - m <- in - close(m) - return - } - } - } - println("Should never be reached") - return - } - close(m) + if first { + if !checkSOA(in, true) { + c.Close() + continue SERVER + } + m <- in + first = !first + } + + if !first { + if !checkSOA(in, false) { + // Soa record not the last one + m <- in + continue + } else { + c.Close() + m <- in + close(m) + return + } + } + } + println("Should never be reached") + return + } + close(m) return } @@ -251,7 +251,7 @@ func exchangeTCP(c net.Conn, m []byte, r *Resolver, send bool) (*Msg, os.Error) for a := 0; a < attempts; a++ { // only send something when told so if send { - err := sendTCP(m,c) + err := sendTCP(m, c) if err != nil { if e, ok := err.(net.Error); ok && e.Timeout() { continue @@ -278,66 +278,66 @@ func exchangeTCP(c net.Conn, m []byte, r *Resolver, send bool) (*Msg, os.Error) return nil, &Error{Error: servErr} } -func sendUDP(m []byte,c net.Conn) os.Error { - _, err := c.Write(m) - if err != nil { - return err - } - return nil +func sendUDP(m []byte, c net.Conn) os.Error { + _, err := c.Write(m) + if err != nil { + return err + } + return nil } func recvUDP(c net.Conn) ([]byte, os.Error) { - m := make([]byte, DefaultMsgSize) // More than enough??? - n, err := c.Read(m) - if err != nil { - return nil, err - } - m = m[:n] - return m, nil + m := make([]byte, DefaultMsgSize) // More than enough??? + n, err := c.Read(m) + if err != nil { + return nil, err + } + m = m[:n] + return m, nil } func sendTCP(m []byte, c net.Conn) 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 + 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 } func recvTCP(c net.Conn) ([]byte, os.Error) { - l := make([]byte, 2) // receiver length - // The server replies with two bytes length - _, err := c.Read(l) - if err != nil { - return nil,err - } - length := uint16(l[0])<<8 | uint16(l[1]) - if length == 0 { - return nil, &Error{Error: "received nil msg length", Server: c.RemoteAddr().String()} - } - m := make([]byte, length) - n, cerr := c.Read(m) - if cerr != nil { - return nil, cerr - } - i := n - if i < int(length) { - n, err = c.Read(m[i:]) - if err != nil { - return nil, err - } - i += n - } - return m, nil + l := make([]byte, 2) // receiver length + // The server replies with two bytes length + _, err := c.Read(l) + if err != nil { + return nil, err + } + length := uint16(l[0])<<8 | uint16(l[1]) + if length == 0 { + return nil, &Error{Error: "received nil msg length", Server: c.RemoteAddr().String()} + } + m := make([]byte, length) + n, cerr := c.Read(m) + if cerr != nil { + return nil, cerr + } + i := n + if i < int(length) { + n, err = c.Read(m[i:]) + if err != nil { + return nil, err + } + i += n + } + return m, nil } // Check if he SOA record exists in the Answer section of