mirror of
https://github.com/miekg/dns.git
synced 2025-08-14 13:36:59 +02:00
* Remove fullSize return from compressionLenSearch This wasn't used anywhere but TestCompressionLenSearch, and was very wrong. * Add generated compressedLen functions and use them This replaces the confusing and complicated compressionLenSlice function. * Use compressedLenWithCompressionMap even for uncompressed This leaves the len() functions unused and they'll soon be removed. This also fixes the off-by-one error of compressedLen when a (Q)NAME is ".". * Use Len helper instead of RR.len private method * Merge len and compressedLen functions * Merge compressedLen helper into Msg.Len * Remove compress bool from compressedLenWithCompressionMap * Merge map insertion into compressionLenSearch This eliminates the need to loop over the domain name twice when we're compressing the name. * Use compressedNameLen for NSEC.NextDomain This was a mistake. * Remove compress from RR.len * Add test case for multiple questions length * Add test case for MINFO and SOA compression These are the only RRs with multiple compressible names within the same RR, and they were previously broken. * Rename compressedNameLen to domainNameLen It also handles the length of uncompressed domain names. * Use off directly instead of len(s[:off]) * Move initial maxCompressionOffset check out of compressionLenMapInsert This should allow us to avoid the call overhead of compressionLenMapInsert in certain limited cases and may result in a slight performance increase. compressionLenMapInsert still has a maxCompressionOffset check inside the for loop. * Rename compressedLenWithCompressionMap to msgLenWithCompressionMap This better reflects that it also calculates the uncompressed length. * Merge TestMsgCompressMINFO with TestMsgCompressSOA They're both testing the same thing. * Remove compressionLenMapInsert compressionLenSearch does everything compressionLenMapInsert did anyway. * Only call compressionLenSearch in one place in domainNameLen * Split if statement in domainNameLen The last two commits worsened the performance of domainNameLen noticably, this change restores it's original performance. name old time/op new time/op delta MsgLength-12 550ns ±13% 510ns ±21% ~ (p=0.050 n=10+10) MsgLengthNoCompression-12 26.9ns ± 2% 27.0ns ± 1% ~ (p=0.198 n=9+10) MsgLengthPack-12 2.30µs ±12% 2.26µs ±16% ~ (p=0.739 n=10+10) MsgLengthMassive-12 32.9µs ± 7% 32.0µs ±10% ~ (p=0.243 n=9+10) MsgLengthOnlyQuestion-12 9.60ns ± 1% 9.20ns ± 1% -4.16% (p=0.000 n=9+9) * Remove stray newline from TestMsgCompressionMultipleQuestions * Remove stray newline in length_test.go This was introduced when resolving merge conflicts.
103 lines
2.7 KiB
Go
103 lines
2.7 KiB
Go
package dns
|
|
|
|
import "strconv"
|
|
|
|
const (
|
|
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
|
defaultTtl = 3600 // Default internal TTL.
|
|
|
|
// DefaultMsgSize is the standard default for messages larger than 512 bytes.
|
|
DefaultMsgSize = 4096
|
|
// MinMsgSize is the minimal size of a DNS packet.
|
|
MinMsgSize = 512
|
|
// MaxMsgSize is the largest possible DNS packet.
|
|
MaxMsgSize = 65535
|
|
)
|
|
|
|
// Error represents a DNS error.
|
|
type Error struct{ err string }
|
|
|
|
func (e *Error) Error() string {
|
|
if e == nil {
|
|
return "dns: <nil>"
|
|
}
|
|
return "dns: " + e.err
|
|
}
|
|
|
|
// An RR represents a resource record.
|
|
type RR interface {
|
|
// Header returns the header of an resource record. The header contains
|
|
// everything up to the rdata.
|
|
Header() *RR_Header
|
|
// String returns the text representation of the resource record.
|
|
String() string
|
|
|
|
// copy returns a copy of the RR
|
|
copy() RR
|
|
|
|
// len returns the length (in octets) of the compressed or uncompressed RR in wire format.
|
|
//
|
|
// If compression is nil, the uncompressed size will be returned, otherwise the compressed
|
|
// size will be returned and domain names will be added to the map for future compression.
|
|
len(off int, compression map[string]struct{}) int
|
|
|
|
// pack packs an RR into wire format.
|
|
pack([]byte, int, map[string]int, bool) (int, error)
|
|
}
|
|
|
|
// RR_Header is the header all DNS resource records share.
|
|
type RR_Header struct {
|
|
Name string `dns:"cdomain-name"`
|
|
Rrtype uint16
|
|
Class uint16
|
|
Ttl uint32
|
|
Rdlength uint16 // Length of data after header.
|
|
}
|
|
|
|
// Header returns itself. This is here to make RR_Header implements the RR interface.
|
|
func (h *RR_Header) Header() *RR_Header { return h }
|
|
|
|
// Just to implement the RR interface.
|
|
func (h *RR_Header) copy() RR { return nil }
|
|
|
|
func (h *RR_Header) String() string {
|
|
var s string
|
|
|
|
if h.Rrtype == TypeOPT {
|
|
s = ";"
|
|
// and maybe other things
|
|
}
|
|
|
|
s += sprintName(h.Name) + "\t"
|
|
s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
|
|
s += Class(h.Class).String() + "\t"
|
|
s += Type(h.Rrtype).String() + "\t"
|
|
return s
|
|
}
|
|
|
|
func (h *RR_Header) len(off int, compression map[string]struct{}) int {
|
|
l := domainNameLen(h.Name, off, compression, true)
|
|
l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
|
|
return l
|
|
}
|
|
|
|
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
|
|
func (rr *RFC3597) ToRFC3597(r RR) error {
|
|
buf := make([]byte, Len(r)*2)
|
|
off, err := PackRR(r, buf, 0, nil, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
buf = buf[:off]
|
|
if int(r.Header().Rdlength) > off {
|
|
return ErrBuf
|
|
}
|
|
|
|
rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*rr = *rfc3597.(*RFC3597)
|
|
return nil
|
|
}
|