diff --git a/dns_test.go b/dns_test.go index d5127bf2..53ad00c0 100644 --- a/dns_test.go +++ b/dns_test.go @@ -111,8 +111,24 @@ func TestPack(t *testing.T) { t.Fail() } } - ns := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org") - t.Log("ns", ns.String()) + x := new(Msg) + ns, _ := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org") + ns.(*RR_NS).Ns = "a.ntpns.org." + x.Ns = append(m.Ns, ns) + x.Ns = append(m.Ns, ns) + x.Ns = append(m.Ns, ns) + // This crashes due to the fact the a.ntpns.org isn't a FQDN + // How to recover() from a remove panic()? + if _, ok := x.Pack(); !ok { + t.Log("Packing failed") + t.Fail() + } + x.Answer = make([]RR, 1) + x.Answer[0], err = NewRR(rr[0]) + if _, ok := x.Pack(); !ok { + t.Log("Packing failed") + t.Fail() + } } func TestCompressLenght(t *testing.T) { diff --git a/msg.go b/msg.go index 34d460e2..d310184f 100644 --- a/msg.go +++ b/msg.go @@ -205,8 +205,7 @@ func PackDomainName(s string, msg []byte, off int, compression map[string]int, c // Add trailing dot to canonicalize name. lenmsg := len(msg) if n := len(s); n == 0 || s[n-1] != '.' { - // Make it fully qualified - s += "." + panic("dns: name not fully qualified") } // Each dot ends a segment of the name. // We trade each dot byte for a length byte. @@ -235,13 +234,23 @@ func PackDomainName(s string, msg []byte, off int, compression map[string]int, c if i-begin >= 1<<6 { // top two bits of length must be clear return lenmsg, false } + // off can already (we're in a loop) be bigger than len(msg) + // this happens when a name isn't fully qualified + if off+1 > len(msg) { + return lenmsg, false + } msg[off] = byte(i - begin) offset := off off++ + // TODO(mg): because of the new check above, this can go. But + // just leave it as is for the moment. if off > lenmsg { return lenmsg, false } for j := begin; j < i; j++ { + if off+1 > len(msg) { + return lenmsg, false + } msg[off] = bs[j] off++ if off > lenmsg { @@ -1210,7 +1219,7 @@ func (dns *Msg) Pack() (msg []byte, ok bool) { dh.Arcount = uint16(len(extra)) // TODO(mg): still a little too much, but better than 64K... - msg = make([]byte, dns.Len()+1) + msg = make([]byte, dns.Len()+10) // Pack it in: header and then the pieces. off := 0 @@ -1328,7 +1337,8 @@ func (dns *Msg) String() string { // Len return the message length when in (un)compressed wire format. // If dns.Compress is true compression is taken into account, currently -// this only counts owner name compression. +// this only counts owner name compression. There is no check for +// nil valued sections (allocated, but contains no RRs). func (dns *Msg) Len() int { // Message header is always 12 bytes l := 12 diff --git a/server.go b/server.go index 1eef6034..5d2345d8 100644 --- a/server.go +++ b/server.go @@ -256,7 +256,7 @@ forever: } go d.serve() } - panic("not reached") + panic("dns: not reached") } // ServeUDP starts a UDP listener for the server. @@ -290,7 +290,7 @@ func (srv *Server) ServeUDP(l *net.UDPConn) error { } go d.serve() } - panic("not reached") + panic("dns: not reached") } func newConn(t *net.TCPConn, u *net.UDPConn, a net.Addr, buf []byte, handler Handler, tsig map[string]string) (*conn, error) { diff --git a/tsig.go b/tsig.go index 43ed9fb5..48a916d5 100644 --- a/tsig.go +++ b/tsig.go @@ -155,7 +155,7 @@ type timerWireFmt struct { // If something goes wrong an error is returned, otherwise it is nil. func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) { if m.IsTsig() == nil { - panic("TSIG not last RR in additional") + panic("dns: TSIG not last RR in additional") } // If we barf here, the caller is to blame rawsecret, err := packBase64([]byte(secret)) diff --git a/types.go b/types.go index 47b64f90..2d3031ed 100644 --- a/types.go +++ b/types.go @@ -883,7 +883,7 @@ func (rr *RR_NSEC) String() string { func (rr *RR_NSEC) Len() int { l := len(rr.NextDomain) + 1 - return rr.Hdr.Len() + l + 32 + return rr.Hdr.Len() + l + 32 + 1 // TODO: +32 is max type bitmap } @@ -1420,7 +1420,7 @@ func cmToString(mantissa, exponent uint8) string { } return s } - panic("not reached") + panic("dns: not reached") } // Map of constructors for each RR wire type. diff --git a/update.go b/update.go index 0fb549f6..f60466fa 100644 --- a/update.go +++ b/update.go @@ -57,7 +57,7 @@ func (u *Msg) NameNotUsed(rr []RR) { // "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2. func (u *Msg) RRsetUsedRdata(rr []RR) { if len(u.Question) == 0 { - panic("empty question section") + panic("dns: empty question section") } u.Answer = make([]RR, len(rr)) for i, r := range rr { @@ -104,7 +104,7 @@ func (u *Msg) RRsetNotUsed(rr []RR) { // RRsetAddRdata creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1 func (u *Msg) RRsetAddRdata(rr []RR) { if len(u.Question) == 0 { - panic("empty question section") + panic("dns: empty question section") } u.Ns = make([]RR, len(rr)) for i, r := range rr { diff --git a/xfr.go b/xfr.go index 4ca8d32b..fb3ac8e9 100644 --- a/xfr.go +++ b/xfr.go @@ -50,7 +50,7 @@ func (c *Client) XfrReceive(q *Msg, a string) (chan *XfrMsg, error) { default: return nil, ErrXfrType } - panic("not reached") + panic("dns: not reached") } func (w *reply) axfrReceive(c chan *XfrMsg) { @@ -84,7 +84,7 @@ func (w *reply) axfrReceive(c chan *XfrMsg) { c <- &XfrMsg{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr(), Error: nil} } } - panic("not reached") + panic("dns: not reached") } func (w *reply) ixfrReceive(c chan *XfrMsg) { @@ -132,7 +132,7 @@ func (w *reply) ixfrReceive(c chan *XfrMsg) { c <- &XfrMsg{Request: w.req, Reply: in, Rtt: w.rtt, RemoteAddr: w.conn.RemoteAddr()} } } - panic("not reached") + panic("dns: not reached") } // XfrSend performs an outgoing Ixfr or Axfr. The function is [AI]xfr agnostic, it is diff --git a/zgenerate.go b/zgenerate.go index c4fb0fe6..f8635215 100644 --- a/zgenerate.go +++ b/zgenerate.go @@ -155,5 +155,5 @@ func modToPrintf(s string) (string, int, string) { default: return "%0" + xs[1] + xs[2], offset, "" } - panic("not reached") + panic("dns: not reached") }