From 19bfc93c5ade90e6d361d113cad6950e408ac7f8 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Mon, 18 Apr 2011 22:08:12 +0200 Subject: [PATCH] remove config.go --- Makefile | 1 - client.go | 104 +++++++++++++++++++---------------- config.go | 13 ----- defaults.go | 23 +++++++- server.go | 154 ++++++++++++++++++++++++++-------------------------- tsig.go | 139 +++++++++++++++++------------------------------ xfr.go | 30 +++++----- 7 files changed, 217 insertions(+), 247 deletions(-) delete mode 100644 config.go diff --git a/Makefile b/Makefile index 59ba6df8..cadfb7df 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,6 @@ TARG=dns GOFILES=\ clientconfig.go\ client.go\ - config.go\ defaults.go\ dns.go\ dnssec.go\ diff --git a/client.go b/client.go index ed733424..98f04d94 100644 --- a/client.go +++ b/client.go @@ -28,10 +28,11 @@ type RequestWriter interface { // hijacked connections...? type reply struct { - client *Client - addr string - req *Msg - conn net.Conn + client *Client + addr string + req *Msg + conn net.Conn + tsigTimersOnly bool } type Request struct { @@ -118,14 +119,15 @@ func (mux *QueryMux) QueryDNS(w RequestWriter, r *Msg) { // TODO add: LocalAddr type Client struct { - Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one - Addr string // address to call - Attempts int // number of attempts - Retry bool // retry with TCP - ChannelQuery chan *Request // read DNS request from this channel - ChannelReply chan []*Msg // read DNS request from this channel - ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections - WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections + Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one + Addr string // address to call + Attempts int // number of attempts + Retry bool // retry with TCP + ChannelQuery chan *Request // read DNS request from this channel + ChannelReply chan []*Msg // read DNS request from this channel + ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections + WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections + TsigSecret map[string]string // secret(s) for Tsig map[] } func NewClient() *Client { @@ -234,15 +236,15 @@ func (w *reply) Receive() (*Msg, os.Error) { p = make([]byte, MaxMsgSize) case "udp": p = make([]byte, DefaultMsgSize) - } - n, err := w.readClient(p) - if err != nil { - return nil, err - } - p = p[:n] - if ok := m.Unpack(p); !ok { - return nil, ErrUnpack - } + } + n, err := w.readClient(p) + if err != nil { + return nil, err + } + p = p[:n] + if ok := m.Unpack(p); !ok { + return nil, ErrUnpack + } return m, nil } @@ -253,32 +255,32 @@ func (w *reply) readClient(p []byte) (n int, err os.Error) { switch w.Client().Net { case "tcp": if len(p) < 1 { - return 0, io.ErrShortBuffer - } - n, err = w.conn.(*net.TCPConn).Read(p[0:2]) - if err != nil || n != 2 { - return n, err - } - l, _ := unpackUint16(p[0:2], 0) - if l == 0 { - return 0, ErrShortRead - } - if int(l) > len(p) { - return int(l), io.ErrShortBuffer - } - n, err = w.conn.(*net.TCPConn).Read(p[:l]) - if err != nil { - return n, err - } - i := n - for i < int(l) { - j, err := w.conn.(*net.TCPConn).Read(p[i:int(l)]) - if err != nil { - return i, err - } - i += j - } - n = i + return 0, io.ErrShortBuffer + } + n, err = w.conn.(*net.TCPConn).Read(p[0:2]) + if err != nil || n != 2 { + return n, err + } + l, _ := unpackUint16(p[0:2], 0) + if l == 0 { + return 0, ErrShortRead + } + if int(l) > len(p) { + return int(l), io.ErrShortBuffer + } + n, err = w.conn.(*net.TCPConn).Read(p[:l]) + if err != nil { + return n, err + } + i := n + for i < int(l) { + j, err := w.conn.(*net.TCPConn).Read(p[i:int(l)]) + if err != nil { + return i, err + } + i += j + } + n = i case "udp": n, _, err = w.conn.(*net.UDPConn).ReadFromUDP(p) if err != nil { @@ -288,7 +290,15 @@ func (w *reply) readClient(p []byte) (n int, err os.Error) { return } +// Send a msg to the address specified in w. +// If the message m contains a TSIG record the transaction +// signature is calculated. func (w *reply) Send(m *Msg) os.Error { + if m.IsTsig() { + // Do tsig + + } + out, ok := m.Pack() if !ok { return ErrPack diff --git a/config.go b/config.go deleted file mode 100644 index c7fb6da6..00000000 --- a/config.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Generic configuration that is used for nameserver. -// It is meant to be as generic as possible. - -package dns - -type Config interface { - // Returns any Tsig information. - Tsig() *Tsig -} diff --git a/defaults.go b/defaults.go index 3f9eb120..3e216d8c 100644 --- a/defaults.go +++ b/defaults.go @@ -47,7 +47,7 @@ func (dns *Msg) IsNotify() (ok bool) { ok = dns.MsgHdr.Opcode == OpcodeNotify ok = ok && dns.Question[0].Qclass == ClassINET ok = ok && dns.Question[0].Qtype == TypeSOA - return ok + return } // Create a dns msg suitable for requesting an ixfr. @@ -78,7 +78,7 @@ func (dns *Msg) IsAxfr() (ok bool) { ok = dns.MsgHdr.Opcode == OpcodeQuery ok = ok && dns.Question[0].Qclass == ClassINET ok = ok && dns.Question[0].Qtype == TypeAXFR - return ok + return } // Is the message a valid ixfr request packet? @@ -89,5 +89,22 @@ func (dns *Msg) IsIxfr() (ok bool) { ok = dns.MsgHdr.Opcode == OpcodeQuery ok = ok && dns.Question[0].Qclass == ClassINET ok = ok && dns.Question[0].Qtype == TypeIXFR - return ok + return +} + +// Has a message a TSIG record as the last record? +func (dns *Msg) IsTsig() (ok bool) { + if len(dns.Extra) > 0 { + return dns.Extra[0].Header().Rrtype == TypeTSIG + } + return +} + +func (dns *Msg) SetTsig(z, algo string, fudge uint16, timesigned uint64) { + t := new(RR_TSIG) + t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0} + t.Algorithm = algo + t.Fudge = fudge + t.TimeSigned = timesigned + dns.Extra = append(dns.Extra, t) } diff --git a/server.go b/server.go index b3c0ff7d..f08c1a35 100644 --- a/server.go +++ b/server.go @@ -70,19 +70,19 @@ func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) { // Helper handlers func Refused(w ResponseWriter, r *Msg) { - m := new(Msg) - m.SetReply(r) - m.MsgHdr.Rcode = RcodeRefused - m.MsgHdr.Authoritative = false - buf, _ := m.Pack() - w.Write(buf) + m := new(Msg) + m.SetReply(r) + m.MsgHdr.Rcode = RcodeRefused + m.MsgHdr.Authoritative = false + buf, _ := m.Pack() + w.Write(buf) } // RefusedHandler return a REFUSED answer func RefusedHandler() Handler { return HandlerFunc(Refused) } func ListenAndServe(addr string, network string, handler Handler) os.Error { - server := &Server{Addr: addr, Network: network, Handler: handler} + server := &Server{Addr: addr, Net: network, Handler: handler} return server.ListenAndServe() } @@ -90,19 +90,19 @@ func zoneMatch(pattern, zone string) (ok bool) { if len(pattern) == 0 { return } - i:=0 - for { - ok = pattern[len(pattern)-1-i] == zone[len(zone)-1-i] - i++ + i := 0 + for { + ok = pattern[len(pattern)-1-i] == zone[len(zone)-1-i] + i++ - if !ok { - break - } - if len(pattern)-1-i < 0 || len(zone)-1-i < 0{ - break - } + if !ok { + break + } + if len(pattern)-1-i < 0 || len(zone)-1-i < 0 { + break + } - } + } return } @@ -125,11 +125,11 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { if pattern == "" { panic("dns: invalid pattern " + pattern) } - if pattern[len(pattern)-1] != '.' { // no ending . - mux.m[pattern + "."] = handler - } else { - mux.m[pattern]= handler - } + if pattern[len(pattern)-1] != '.' { // no ending . + mux.m[pattern+"."] = handler + } else { + mux.m[pattern] = handler + } } func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { @@ -158,7 +158,7 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) { // A Server defines parameters for running an DNS server. type Server struct { Addr string // address to listen on, ":dns" if empty - Network string // if "tcp" it will invoke a TCP listener, otherwise an UDP one + Net string // if "tcp" it will invoke a TCP listener, otherwise an UDP one Handler Handler // handler to invoke, dns.DefaultServeMux if nil ReadTimeout int64 // the net.Conn.SetReadTimeout value for new connections WriteTimeout int64 // the net.Conn.SetWriteTimeout value for new connections @@ -169,7 +169,7 @@ type Server struct { // read requests and then call handler to reply to them. // Handler is typically nil, in which case the DefaultServeMux is used. func ServeTCP(l *net.TCPListener, handler Handler) os.Error { - srv := &Server{Handler: handler, Network: "tcp"} + srv := &Server{Handler: handler, Net: "tcp"} return srv.ServeTCP(l) } @@ -178,7 +178,7 @@ func ServeTCP(l *net.TCPListener, handler Handler) os.Error { // read requests and then call handler to reply to them. // Handler is typically nil, in which case the DefaultServeMux is used. func ServeUDP(l *net.UDPConn, handler Handler) os.Error { - srv := &Server{Handler: handler, Network: "udp"} + srv := &Server{Handler: handler, Net: "udp"} return srv.ServeUDP(l) } @@ -188,7 +188,7 @@ func (srv *Server) ListenAndServe() os.Error { if addr == "" { addr = ":domain" } - switch srv.Network { + switch srv.Net { case "tcp": a, e := net.ResolveTCPAddr(addr) if e != nil { @@ -323,60 +323,60 @@ func (c *conn) close() { // Serve a new connection. func (c *conn) serve() { - for { - // Request has been read in ServeUDP or ServeTCP - w := new(response) - w.conn = c - req := new(Msg) - if !req.Unpack(c.request) { - break - } - w.req = req - c.handler.ServeDNS(w, w.req) // this does the writing back to the client - if c.hijacked { - return - } - break // TODO(mg) Why is this a loop anyway - } - if c._TCP != nil { - c.close() // Listen and Serve is closed then - } + for { + // Request has been read in ServeUDP or ServeTCP + w := new(response) + w.conn = c + req := new(Msg) + if !req.Unpack(c.request) { + break + } + w.req = req + c.handler.ServeDNS(w, w.req) // this does the writing back to the client + if c.hijacked { + return + } + break // TODO(mg) Why is this a loop anyway + } + if c._TCP != nil { + c.close() // Listen and Serve is closed then + } } func (w *response) Write(data []byte) (n int, err os.Error) { - switch { - case w.conn._UDP != nil: - n, err = w.conn._UDP.WriteTo(data, w.conn.remoteAddr) - if err != nil { - return 0, err - } - case w.conn._TCP != nil: - // TODO(mg) len(data) > 64K - l := make([]byte, 2) - l[0], l[1] = packUint16(uint16(len(data))) - n, err = w.conn._TCP.Write(l) - if err != nil { - return n, err - } - if n != 2 { - return n, io.ErrShortWrite - } - n, err = w.conn._TCP.Write(data) - if err != nil { - return n, err - } - i := n - if i < len(data) { - j, err := w.conn._TCP.Write(data[i:len(data)]) - if err != nil { - return i, err - } - i += j - } - n = i - } - return n, nil + switch { + case w.conn._UDP != nil: + n, err = w.conn._UDP.WriteTo(data, w.conn.remoteAddr) + if err != nil { + return 0, err + } + case w.conn._TCP != nil: + // TODO(mg) len(data) > 64K + l := make([]byte, 2) + l[0], l[1] = packUint16(uint16(len(data))) + n, err = w.conn._TCP.Write(l) + if err != nil { + return n, err + } + if n != 2 { + return n, io.ErrShortWrite + } + n, err = w.conn._TCP.Write(data) + if err != nil { + return n, err + } + i := n + if i < len(data) { + j, err := w.conn._TCP.Write(data[i:len(data)]) + if err != nil { + return i, err + } + i += j + } + n = i + } + return n, nil } // RemoteAddr implements the ResponseWriter.RemoteAddr method diff --git a/tsig.go b/tsig.go index 3708b3aa..f2506fc0 100644 --- a/tsig.go +++ b/tsig.go @@ -21,49 +21,6 @@ import ( // tsig.TimeSigned = uint64(time.Seconds()) // tsig.Secret = "so6ZGir4GPAqINNh9U5c3A==" // Secret encoded in base64. -type TsigWriter struct { - secrets map[string]string - w io.Writer - name string - fudge uint16 - algorithm string - timersOnly bool -} - -// NewTsigWriter creates a new writer that implements TSIG, secrets -// should contain a mapping from key names to secrets. A message -// should be written with the TSIG record appends. Tsig -func NewTsigWriter(w io.Writer, secrets map[string]string) *TsigWriter { - t := new(TsigWriter) - t.secrets = secrets - return t -} - -func (t *TsigWriter) Write(p []byte) (int, os.Error) { - return 0, nil - -} - - -type Tsig struct { - // The name of the key. - Name string - // Fudge to take into account. - Fudge uint16 - // When is the TSIG created - TimeSigned uint64 - // Which algorithm is used. - Algorithm string - // Tsig secret encoded in base64. - Secret string - // MAC (if known) - MAC string - // Request MAC - RequestMAC string - // Only include the timers in the MAC if set to true. - TimersOnly bool -} - // HMAC hashing codes. These are transmitted as domain names. const ( HmacMD5 = "hmac-md5.sig-alg.reg.int." @@ -101,50 +58,42 @@ type timerWireFmt struct { Fudge uint16 } -// Add a Tsig to add message. -func (t *Tsig) Generate(msg []byte) ([]byte, os.Error) { - rawsecret, err := packBase64([]byte(t.Secret)) +// Add a Tsig to an message. // Must return the mac +func TsigGenerate(m *Msg, secret string, timersOnly bool) (*Msg, os.Error) { + if !m.IsTsig() { + panic("TSIG not last RR in additional") + } + rawsecret, err := packBase64([]byte(secret)) if err != nil { return nil, err } - if t.Fudge == 0 { - t.Fudge = 300 - } - if t.TimeSigned == 0 { - t.TimeSigned = uint64(time.Seconds()) - } - buf, err := t.Buffer(msg) + rr := m.Extra[len(m.Extra)-1].(*RR_TSIG) + m.Extra = m.Extra[0:len(m.Extra)-1] // kill the TSIG from the msg + buf, err := tsigBuffer(m, rr, timersOnly) if err != nil { return nil, err } + + t := new(RR_TSIG) + h := hmac.NewMD5([]byte(rawsecret)) io.WriteString(h, string(buf)) t.MAC = hex.EncodeToString(h.Sum()) // Size is half! - // Create TSIG and add it to the message. - q := new(Msg) - if !q.Unpack(msg) { - return nil, ErrUnpack - } + t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0} + t.Fudge = t.Fudge + t.TimeSigned = t.TimeSigned + t.Algorithm = t.Algorithm + t.OrigId = m.MsgHdr.Id + t.MAC = t.MAC + t.MACSize = uint16(len(t.MAC) / 2) - rr := new(RR_TSIG) - rr.Hdr = RR_Header{Name: t.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0} - rr.Fudge = t.Fudge - rr.TimeSigned = t.TimeSigned - rr.Algorithm = t.Algorithm - rr.OrigId = q.Id - rr.MAC = t.MAC - rr.MACSize = uint16(len(t.MAC) / 2) - - q.Extra = append(q.Extra, rr) - send, ok := q.Pack() - if !ok { - return send, ErrPack - } - return send, nil + m.Extra = append(m.Extra, t) + return m, nil } +/* // Verify a TSIG on a message. // If the signature does not validate err contains the // error. If the it validates err is nil @@ -164,25 +113,32 @@ func (t *Tsig) Verify(msg []byte) (bool, os.Error) { return false, err } - // Time needs to be checked */ + // Time needs to be checked h := hmac.NewMD5([]byte(rawsecret)) io.WriteString(h, string(buf)) return strings.ToUpper(hex.EncodeToString(h.Sum())) == strings.ToUpper(t.MAC), nil } +*/ // Create a wiredata buffer for the MAC calculation. -func (t *Tsig) Buffer(msg []byte) ([]byte, os.Error) { +func tsigBuffer(msg *Msg, rr *RR_TSIG, timersOnly bool) ([]byte, os.Error) { var ( macbuf []byte buf []byte ) + if rr.TimeSigned == 0 { + rr.TimeSigned = uint64(time.Seconds()) + } + if rr.Fudge == 0 { + rr.Fudge = 300 + } - if t.RequestMAC != "" { + if rr.MAC != "" { m := new(macWireFmt) - m.MACSize = uint16(len(t.RequestMAC) / 2) - m.MAC = t.RequestMAC - macbuf = make([]byte, len(t.RequestMAC)) // reqmac should be twice as long + m.MACSize = uint16(len(rr.MAC) / 2) + m.MAC = rr.MAC + macbuf = make([]byte, len(rr.MAC)) // reqmac should be twice as long n, ok := packStruct(m, macbuf, 0) if !ok { return nil, ErrSigGen @@ -191,10 +147,10 @@ func (t *Tsig) Buffer(msg []byte) ([]byte, os.Error) { } tsigvar := make([]byte, DefaultMsgSize) - if t.TimersOnly { + if timersOnly { tsig := new(timerWireFmt) - tsig.TimeSigned = t.TimeSigned - tsig.Fudge = t.Fudge + tsig.TimeSigned = rr.TimeSigned + tsig.Fudge = rr.Fudge n, ok1 := packStruct(tsig, tsigvar, 0) if !ok1 { return nil, ErrSigGen @@ -202,12 +158,12 @@ func (t *Tsig) Buffer(msg []byte) ([]byte, os.Error) { tsigvar = tsigvar[:n] } else { tsig := new(tsigWireFmt) - tsig.Name = strings.ToLower(t.Name) + tsig.Name = strings.ToLower(rr.Hdr.Name) tsig.Class = ClassANY tsig.Ttl = 0 - tsig.Algorithm = strings.ToLower(t.Algorithm) - tsig.TimeSigned = t.TimeSigned - tsig.Fudge = t.Fudge + tsig.Algorithm = strings.ToLower(rr.Algorithm) + tsig.TimeSigned = rr.TimeSigned + tsig.Fudge = rr.Fudge tsig.Error = 0 tsig.OtherLen = 0 tsig.OtherData = "" @@ -217,15 +173,17 @@ func (t *Tsig) Buffer(msg []byte) ([]byte, os.Error) { } tsigvar = tsigvar[:n] } - if t.RequestMAC != "" { - x := append(macbuf, msg...) + if rr.MAC != "" { + msgbuf, _ := msg.Pack() + x := append(macbuf, msgbuf...) buf = append(x, tsigvar...) } else { - buf = append(msg, tsigvar...) + msgbuf, _ := msg.Pack() + buf = append(msgbuf, tsigvar...) } return buf, nil } - +/* // Strip the TSIG from the pkt. func (t *Tsig) stripTsig(orig []byte) ([]byte, os.Error) { // Copied from msg.go's Unpack() @@ -292,3 +250,4 @@ func (t *Tsig) stripTsig(orig []byte) ([]byte, os.Error) { } return msg[:tsigoff], nil } +*/ diff --git a/xfr.go b/xfr.go index 868b1433..6b3a6d82 100644 --- a/xfr.go +++ b/xfr.go @@ -8,31 +8,31 @@ import ( // section contains an AXFR type an Axfr is performed. If q's question // section contains an IXFR type an Ixfr is performed. func (c *Client) XfrReceive(q *Msg, a string) ([]*Msg, os.Error) { - w := new(reply) - w.client = c - w.addr = a - w.req = q // is this needed?? + w := new(reply) + w.client = c + w.addr = a + w.req = q // is this needed TODO(mg) if err := w.Send(q); err != nil { - return nil, err - } - // conn should be set now + return nil, err + } + // conn should be set now switch q.Question[0].Qtype { case TypeAXFR: return w.axfrReceive() case TypeIXFR: - // return w.ixfrReceive() + // return w.ixfrReceive() } - panic("not reached") - return nil, nil + panic("not reached") + return nil, nil } func (w *reply) axfrReceive() ([]*Msg, os.Error) { - axfr := make([]*Msg, 0) // use append ALL the time? - first := true + axfr := make([]*Msg, 0) // use append ALL the time? + first := true for { in, err := w.Receive() - axfr = append(axfr, in) + axfr = append(axfr, in) if err != nil { return axfr, err } @@ -45,9 +45,7 @@ func (w *reply) axfrReceive() ([]*Msg, os.Error) { } if !first { - //if d.Tsig != nil { - // d.Tsig.TimersOnly = true // Subsequent envelopes use this. - //} + w.tsigTimersOnly = true // Subsequent envelopes use this. if !checkXfrSOA(in, false) { // Soa record not the last one continue