2011-01-27 19:29:11 +11:00
// DNS packet assembly, see RFC 1035. Converting from - Unpack() -
// and to - Pack() - wire format.
// All the packers and unpackers take a (msg []byte, off int)
// and return (off1 int, ok bool). If they return ok==false, they
// also return off1==len(msg), so that the next unpacker will
// also fail. This lets us avoid checks of ok until the end of a
// packing sequence.
2010-08-04 07:57:59 +10:00
package dns
2016-05-15 02:56:20 +10:00
//go:generate go run msg_generate.go
2017-02-17 20:48:37 +11:00
//go:generate go run compress_generate.go
2016-05-15 02:56:20 +10:00
2010-08-04 07:57:59 +10:00
import (
2016-06-05 16:51:30 +10:00
crand "crypto/rand"
"encoding/binary"
2017-03-30 06:43:02 +11:00
"fmt"
2014-12-06 07:16:13 +11:00
"math/big"
2011-12-09 21:16:49 +11:00
"math/rand"
"strconv"
2017-02-05 19:47:07 +11:00
"sync"
2010-08-04 07:57:59 +10:00
)
2017-03-30 06:43:02 +11:00
const (
maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
)
2012-01-11 21:13:17 +11:00
2017-11-04 03:15:35 +11:00
// Errors defined in this package.
2011-03-25 21:20:52 +11:00
var (
2016-06-14 04:44:38 +10:00
ErrAlg error = & Error { err : "bad algorithm" } // ErrAlg indicates an error with the (DNSSEC) algorithm.
ErrAuth error = & Error { err : "bad authentication" } // ErrAuth indicates an error in the TSIG authentication.
2017-04-27 03:46:52 +10:00
ErrBuf error = & Error { err : "buffer size too small" } // ErrBuf indicates that the buffer used is too small for the message.
ErrConnEmpty error = & Error { err : "conn has no connection" } // ErrConnEmpty indicates a connection is being used before it is initialized.
2016-06-14 04:44:38 +10:00
ErrExtendedRcode error = & Error { err : "bad extended rcode" } // ErrExtendedRcode ...
ErrFqdn error = & Error { err : "domain must be fully qualified" } // ErrFqdn indicates that a domain name does not have a closing dot.
ErrId error = & Error { err : "id mismatch" } // ErrId indicates there is a mismatch with the message's ID.
ErrKeyAlg error = & Error { err : "bad key algorithm" } // ErrKeyAlg indicates that the algorithm in the key is not valid.
ErrKey error = & Error { err : "bad key" }
ErrKeySize error = & Error { err : "bad key size" }
2017-03-30 06:43:02 +11:00
ErrLongDomain error = & Error { err : fmt . Sprintf ( "domain name exceeded %d wire-format octets" , maxDomainNameWireOctets ) }
2016-06-14 04:44:38 +10:00
ErrNoSig error = & Error { err : "no signature found" }
ErrPrivKey error = & Error { err : "bad private key" }
ErrRcode error = & Error { err : "bad rcode" }
ErrRdata error = & Error { err : "bad rdata" }
ErrRRset error = & Error { err : "bad rrset" }
ErrSecret error = & Error { err : "no secrets defined" }
ErrShortRead error = & Error { err : "short read" }
ErrSig error = & Error { err : "bad signature" } // ErrSig indicates that a signature can not be cryptographically validated.
ErrSoa error = & Error { err : "no SOA" } // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
ErrTime error = & Error { err : "bad time" } // ErrTime indicates a timing error in TSIG authentication.
ErrTruncated error = & Error { err : "failed to unpack truncated message" } // ErrTruncated indicates that we failed to unpack a truncated message. We unpacked as much as we had so Msg can still be used, if desired.
2011-03-25 21:20:52 +11:00
)
2011-03-25 21:19:35 +11:00
2016-10-04 05:18:08 +11:00
// Id by default, returns a 16 bits random number to be used as a
2014-07-30 16:17:13 +10:00
// message id. The random provided should be good enough. This being a
2014-07-30 16:35:06 +10:00
// variable the function can be reassigned to a custom function.
// For instance, to make it return a static value:
//
// dns.Id = func() uint16 { return 3 }
2017-11-04 03:15:35 +11:00
var Id = id
2014-07-30 16:17:13 +10:00
2017-02-05 19:47:07 +11:00
var (
idLock sync . Mutex
idRand * rand . Rand
)
2016-06-14 04:44:38 +10:00
// id returns a 16 bits random number to be used as a
// message id. The random provided should be good enough.
func id ( ) uint16 {
2017-02-05 19:47:07 +11:00
idLock . Lock ( )
if idRand == nil {
// This (partially) works around
// https://github.com/golang/go/issues/11833 by only
// seeding idRand upon the first call to id.
var seed int64
var buf [ 8 ] byte
if _ , err := crand . Read ( buf [ : ] ) ; err == nil {
seed = int64 ( binary . LittleEndian . Uint64 ( buf [ : ] ) )
} else {
seed = rand . Int63 ( )
}
idRand = rand . New ( rand . NewSource ( seed ) )
}
// The call to idRand.Uint32 must be within the
// mutex lock because *rand.Rand is not safe for
// concurrent use.
//
// There is no added performance overhead to calling
// idRand.Uint32 inside a mutex lock over just
// calling rand.Uint32 as the global math/rand rng
// is internally protected by a sync.Mutex.
id := uint16 ( idRand . Uint32 ( ) )
idLock . Unlock ( )
return id
2016-06-14 04:44:38 +10:00
}
2015-02-19 20:58:33 +11:00
// MsgHdr is a a manually-unpacked version of (id, bits).
2011-01-01 03:05:11 +11:00
type MsgHdr struct {
Id uint16
Response bool
Opcode int
Authoritative bool
Truncated bool
RecursionDesired bool
RecursionAvailable bool
Zero bool
AuthenticatedData bool
CheckingDisabled bool
Rcode int
}
2015-02-19 20:58:33 +11:00
// Msg contains the layout of a DNS message.
2011-01-01 03:05:11 +11:00
type Msg struct {
MsgHdr
2016-06-14 04:44:38 +10:00
Compress bool ` json:"-" ` // If true, the message will be compressed when converted to wire format.
2012-08-08 19:13:28 +10:00
Question [ ] Question // Holds the RR(s) of the question section.
Answer [ ] RR // Holds the RR(s) of the answer section.
Ns [ ] RR // Holds the RR(s) of the authority section.
Extra [ ] RR // Holds the RR(s) of the additional section.
2011-01-01 03:05:11 +11:00
}
2015-02-19 20:58:33 +11:00
// ClassToString is a maps Classes to strings for each CLASS wire type.
2012-12-02 19:29:54 +11:00
var ClassToString = map [ uint16 ] string {
2010-08-04 07:57:59 +10:00
ClassINET : "IN" ,
ClassCSNET : "CS" ,
ClassCHAOS : "CH" ,
ClassHESIOD : "HS" ,
2011-07-24 07:43:43 +10:00
ClassNONE : "NONE" ,
2010-08-04 07:57:59 +10:00
ClassANY : "ANY" ,
}
2015-02-19 20:58:33 +11:00
// OpcodeToString maps Opcodes to strings.
2012-12-02 19:29:54 +11:00
var OpcodeToString = map [ int ] string {
2011-01-02 05:51:25 +11:00
OpcodeQuery : "QUERY" ,
OpcodeIQuery : "IQUERY" ,
OpcodeStatus : "STATUS" ,
OpcodeNotify : "NOTIFY" ,
OpcodeUpdate : "UPDATE" ,
2010-08-04 07:57:59 +10:00
}
2015-02-19 20:58:33 +11:00
// RcodeToString maps Rcodes to strings.
2012-12-02 19:29:54 +11:00
var RcodeToString = map [ int ] string {
2011-01-02 05:51:25 +11:00
RcodeSuccess : "NOERROR" ,
2011-01-02 06:51:34 +11:00
RcodeFormatError : "FORMERR" ,
2011-01-02 05:51:25 +11:00
RcodeServerFailure : "SERVFAIL" ,
RcodeNameError : "NXDOMAIN" ,
RcodeNotImplemented : "NOTIMPL" ,
RcodeRefused : "REFUSED" ,
2016-06-14 04:44:38 +10:00
RcodeYXDomain : "YXDOMAIN" , // See RFC 2136
2011-01-03 20:44:00 +11:00
RcodeYXRrset : "YXRRSET" ,
RcodeNXRrset : "NXRRSET" ,
RcodeNotAuth : "NOTAUTH" ,
RcodeNotZone : "NOTZONE" ,
2013-04-30 23:20:01 +10:00
RcodeBadSig : "BADSIG" , // Also known as RcodeBadVers, see RFC 6891
// RcodeBadVers: "BADVERS",
2016-06-12 22:10:24 +10:00
RcodeBadKey : "BADKEY" ,
RcodeBadTime : "BADTIME" ,
RcodeBadMode : "BADMODE" ,
RcodeBadName : "BADNAME" ,
RcodeBadAlg : "BADALG" ,
RcodeBadTrunc : "BADTRUNC" ,
RcodeBadCookie : "BADCOOKIE" ,
2010-08-04 07:57:59 +10:00
}
// Domain names are a sequence of counted strings
2011-12-17 05:29:24 +11:00
// split at the dots. They end with a zero-length string.
2012-01-17 07:49:17 +11:00
// PackDomainName packs a domain name s into msg[off:].
2012-01-17 07:57:57 +11:00
// If compression is wanted compress must be true and the compression
2012-02-27 04:23:21 +11:00
// map needs to hold a mapping between domain names and offsets
2015-08-08 05:58:26 +10:00
// pointing into msg.
2012-10-10 06:17:54 +11:00
func PackDomainName ( s string , msg [ ] byte , off int , compression map [ string ] int , compress bool ) ( off1 int , err error ) {
2013-09-11 04:09:22 +10:00
off1 , _ , err = packDomainName ( s , msg , off , compression , compress )
return
}
func packDomainName ( s string , msg [ ] byte , off int , compression map [ string ] int , compress bool ) ( off1 int , labels int , err error ) {
// special case if msg == nil
lenmsg := 256
if msg != nil {
lenmsg = len ( msg )
}
2012-08-31 00:45:11 +10:00
ls := len ( s )
2013-08-27 14:11:24 +10:00
if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
2013-09-11 04:09:22 +10:00
return off , 0 , nil
2013-08-27 14:11:24 +10:00
}
2013-09-11 04:09:22 +10:00
// If not fully qualified, error out, but only if msg == nil #ugly
switch {
case msg == nil :
if s [ ls - 1 ] != '.' {
s += "."
ls ++
}
case msg != nil :
if s [ ls - 1 ] != '.' {
return lenmsg , 0 , ErrFqdn
}
2010-08-04 07:57:59 +10:00
}
// Each dot ends a segment of the name.
// We trade each dot byte for a length byte.
2011-02-22 06:33:36 +11:00
// Except for escaped dots (\.), which are normal dots.
2010-08-04 07:57:59 +10:00
// There is also a trailing zero.
2012-02-27 04:23:21 +11:00
2012-01-11 21:44:44 +11:00
// Compression
nameoffset := - 1
pointer := - 1
2010-08-04 07:57:59 +10:00
// Emit sequence of counted strings, chopping at dots.
begin := 0
2014-01-29 09:43:48 +11:00
bs := [ ] byte ( s )
2015-02-19 20:58:33 +11:00
roBs , bsFresh , escapedDot := s , true , false
2011-02-22 06:33:36 +11:00
for i := 0 ; i < ls ; i ++ {
if bs [ i ] == '\\' {
2012-11-15 23:51:15 +11:00
for j := i ; j < ls - 1 ; j ++ {
2011-02-25 02:22:14 +11:00
bs [ j ] = bs [ j + 1 ]
}
ls --
2012-11-15 23:51:15 +11:00
if off + 1 > lenmsg {
2013-09-11 04:09:22 +10:00
return lenmsg , labels , ErrBuf
2012-11-15 23:51:15 +11:00
}
2013-06-14 16:31:22 +10:00
// check for \DDD
2014-02-26 21:33:33 +11:00
if i + 2 < ls && isDigit ( bs [ i ] ) && isDigit ( bs [ i + 1 ] ) && isDigit ( bs [ i + 2 ] ) {
bs [ i ] = dddToByte ( bs [ i : ] )
2012-11-19 22:26:13 +11:00
for j := i + 1 ; j < ls - 2 ; j ++ {
2012-11-15 23:51:15 +11:00
bs [ j ] = bs [ j + 2 ]
}
ls -= 2
}
2015-02-19 20:58:33 +11:00
escapedDot = bs [ i ] == '.'
bsFresh = false
2011-02-25 02:22:14 +11:00
continue
2011-02-22 06:33:36 +11:00
}
if bs [ i ] == '.' {
2015-02-19 20:58:33 +11:00
if i > 0 && bs [ i - 1 ] == '.' && ! escapedDot {
2013-09-11 04:09:22 +10:00
// two dots back to back is not legal
return lenmsg , labels , ErrRdata
}
2011-02-25 02:22:14 +11:00
if i - begin >= 1 << 6 { // top two bits of length must be clear
2013-09-11 04:09:22 +10:00
return lenmsg , labels , ErrRdata
2011-02-25 02:22:14 +11:00
}
2012-08-29 02:21:23 +10:00
// off can already (we're in a loop) be bigger than len(msg)
// this happens when a name isn't fully qualified
2012-10-11 22:06:27 +11:00
if off + 1 > lenmsg {
2013-09-11 04:09:22 +10:00
return lenmsg , labels , ErrBuf
}
if msg != nil {
msg [ off ] = byte ( i - begin )
2012-08-29 02:21:23 +10:00
}
2012-01-11 21:19:07 +11:00
offset := off
2011-02-25 02:22:14 +11:00
off ++
for j := begin ; j < i ; j ++ {
2012-10-11 22:06:27 +11:00
if off + 1 > lenmsg {
2013-09-11 04:09:22 +10:00
return lenmsg , labels , ErrBuf
}
if msg != nil {
msg [ off ] = bs [ j ]
2012-08-29 02:21:23 +10:00
}
2011-02-25 02:22:14 +11:00
off ++
}
2015-02-19 20:58:33 +11:00
if compress && ! bsFresh {
roBs = string ( bs )
bsFresh = true
2014-01-27 07:08:05 +11:00
}
2016-01-20 09:23:11 +11:00
// Don't try to compress '.'
2017-02-17 20:48:37 +11:00
// We should only compress when compress it true, but we should also still pick
// up names that can be used for *future* compression(s).
if compression != nil && roBs [ begin : ] != "." {
2015-02-19 20:58:33 +11:00
if p , ok := compression [ roBs [ begin : ] ] ; ! ok {
2012-01-12 00:09:47 +11:00
// Only offsets smaller than this can be used.
2012-01-11 21:44:44 +11:00
if offset < maxCompressionOffset {
2015-02-19 20:58:33 +11:00
compression [ roBs [ begin : ] ] = offset
2012-01-11 21:44:44 +11:00
}
} else {
// The first hit is the longest matching dname
// keep the pointer offset we get back and store
// the offset of the current name, because that's
// where we need to insert the pointer later
2012-01-12 02:18:17 +11:00
2013-06-27 07:18:09 +10:00
// If compress is true, we're allowed to compress this dname
2012-01-12 02:16:09 +11:00
if pointer == - 1 && compress {
2012-01-11 21:44:44 +11:00
pointer = p // Where to point to
nameoffset = offset // Where to point from
2012-02-27 04:23:21 +11:00
break
2012-01-11 21:44:44 +11:00
}
2012-01-11 21:19:07 +11:00
}
}
2013-09-11 04:09:22 +10:00
labels ++
2011-02-25 02:22:14 +11:00
begin = i + 1
2010-08-04 07:57:59 +10:00
}
2015-02-19 20:58:33 +11:00
escapedDot = false
2010-08-04 07:57:59 +10:00
}
2010-12-24 03:10:06 +11:00
// Root label is special
2013-06-14 21:38:04 +10:00
if len ( bs ) == 1 && bs [ 0 ] == '.' {
2013-09-11 04:09:22 +10:00
return off , labels , nil
2010-12-24 03:10:06 +11:00
}
2013-06-27 07:18:09 +10:00
// If we did compression and we find something add the pointer here
2012-01-11 21:44:44 +11:00
if pointer != - 1 {
2012-01-12 00:09:47 +11:00
// We have two bytes (14 bits) to put the pointer in
2013-09-11 04:09:22 +10:00
// if msg == nil, we will never do compression
2016-06-09 01:38:42 +10:00
binary . BigEndian . PutUint16 ( msg [ nameoffset : ] , uint16 ( pointer ^ 0xC000 ) )
2012-01-12 02:04:52 +11:00
off = nameoffset + 1
goto End
2012-01-11 21:44:44 +11:00
}
2016-05-15 02:56:20 +10:00
if msg != nil && off < len ( msg ) {
2013-09-11 04:09:22 +10:00
msg [ off ] = 0
}
2012-01-12 02:04:52 +11:00
End :
2010-08-04 07:57:59 +10:00
off ++
2013-09-11 04:09:22 +10:00
return off , labels , nil
2010-08-04 07:57:59 +10:00
}
// Unpack a domain name.
// In addition to the simple sequences of counted strings above,
// domain names are allowed to refer to strings elsewhere in the
// packet, to avoid repeating common suffixes when returning
// many entries in a single domain. The pointers are marked
// by a length byte with the top two bits set. Ignoring those
// two bits, that byte and the next give a 14 bit offset from msg[0]
// where we should pick up the trail.
// Note that if we jump elsewhere in the packet,
// we return off1 == the offset after the first pointer we found,
// which is where the next record will start.
// In theory, the pointers are only allowed to jump backward.
// We let them jump anywhere and stop jumping after a while.
2012-01-17 07:49:17 +11:00
2012-01-27 08:52:29 +11:00
// UnpackDomainName unpacks a domain name into a string.
2014-02-01 04:06:23 +11:00
func UnpackDomainName ( msg [ ] byte , off int ) ( string , int , error ) {
s := make ( [ ] byte , 0 , 64 )
off1 := 0
2011-09-20 18:20:24 +10:00
lenmsg := len ( msg )
2017-03-30 06:43:02 +11:00
maxLen := maxDomainNameWireOctets
2010-08-04 07:57:59 +10:00
ptr := 0 // number of pointers followed
Loop :
for {
2011-08-09 19:41:44 +10:00
if off >= lenmsg {
2012-10-10 06:17:54 +11:00
return "" , lenmsg , ErrBuf
2010-08-04 07:57:59 +10:00
}
c := int ( msg [ off ] )
off ++
switch c & 0xC0 {
case 0x00 :
if c == 0x00 {
// end of name
break Loop
}
// literal string
2011-08-09 19:41:44 +10:00
if off + c > lenmsg {
2012-10-10 06:17:54 +11:00
return "" , lenmsg , ErrBuf
2010-08-04 07:57:59 +10:00
}
2011-02-25 02:22:14 +11:00
for j := off ; j < off + c ; j ++ {
2014-02-26 21:33:33 +11:00
switch b := msg [ j ] ; b {
2014-03-02 09:30:52 +11:00
case '.' , '(' , ')' , ';' , ' ' , '@' :
2012-11-16 00:26:08 +11:00
fallthrough
2014-02-26 21:33:33 +11:00
case '"' , '\\' :
s = append ( s , '\\' , b )
2017-03-30 06:43:02 +11:00
// presentation-format \X escapes add an extra byte
2017-11-04 03:15:35 +11:00
maxLen ++
2012-11-16 00:26:08 +11:00
default :
2017-03-30 06:43:02 +11:00
if b < 32 || b >= 127 { // unprintable, use \DDD
2014-11-07 00:46:42 +11:00
var buf [ 3 ] byte
bufs := strconv . AppendInt ( buf [ : 0 ] , int64 ( b ) , 10 )
s = append ( s , '\\' )
for i := 0 ; i < 3 - len ( bufs ) ; i ++ {
s = append ( s , '0' )
}
for _ , r := range bufs {
s = append ( s , r )
}
2017-03-30 06:43:02 +11:00
// presentation-format \DDD escapes add 3 extra bytes
maxLen += 3
2014-02-26 21:33:33 +11:00
} else {
s = append ( s , b )
}
2011-02-25 02:22:14 +11:00
}
}
2014-02-01 04:06:23 +11:00
s = append ( s , '.' )
2010-08-04 07:57:59 +10:00
off += c
case 0xC0 :
// pointer to somewhere else in msg.
// remember location after first ptr,
// since that's how many bytes we consumed.
// also, don't follow too many pointers --
// maybe there's a loop.
2011-08-09 19:41:44 +10:00
if off >= lenmsg {
2012-10-10 06:17:54 +11:00
return "" , lenmsg , ErrBuf
2010-08-04 07:57:59 +10:00
}
c1 := msg [ off ]
off ++
if ptr == 0 {
off1 = off
}
if ptr ++ ; ptr > 10 {
2013-06-20 16:27:28 +10:00
return "" , lenmsg , & Error { err : "too many compression pointers" }
2010-08-04 07:57:59 +10:00
}
2017-03-30 06:43:02 +11:00
// pointer should guarantee that it advances and points forwards at least
// but the condition on previous three lines guarantees that it's
// at least loop-free
2010-08-04 07:57:59 +10:00
off = ( c ^ 0xC0 ) << 8 | int ( c1 )
default :
// 0x80 and 0x40 are reserved
2012-10-10 06:17:54 +11:00
return "" , lenmsg , ErrRdata
2010-08-04 07:57:59 +10:00
}
}
if ptr == 0 {
off1 = off
}
2015-08-05 09:18:02 +10:00
if len ( s ) == 0 {
s = [ ] byte ( "." )
2017-03-30 06:43:02 +11:00
} else if len ( s ) >= maxLen {
// error if the name is too long, but don't throw it away
return string ( s ) , lenmsg , ErrLongDomain
2015-08-05 09:18:02 +10:00
}
2014-02-01 04:06:23 +11:00
return string ( s ) , off1 , nil
2010-08-04 07:57:59 +10:00
}
2014-03-02 09:25:24 +11:00
func packTxt ( txt [ ] string , msg [ ] byte , offset int , tmp [ ] byte ) ( int , error ) {
2014-02-26 21:33:33 +11:00
if len ( txt ) == 0 {
if offset >= len ( msg ) {
return offset , ErrBuf
}
msg [ offset ] = 0
return offset , nil
}
2016-06-09 16:00:08 +10:00
var err error
2014-02-26 21:33:33 +11:00
for i := range txt {
if len ( txt [ i ] ) > len ( tmp ) {
return offset , ErrBuf
}
2014-03-02 09:25:24 +11:00
offset , err = packTxtString ( txt [ i ] , msg , offset , tmp )
2014-02-26 21:33:33 +11:00
if err != nil {
return offset , err
}
}
2016-06-09 16:00:08 +10:00
return offset , nil
2014-02-26 21:33:33 +11:00
}
2014-03-02 09:25:24 +11:00
func packTxtString ( s string , msg [ ] byte , offset int , tmp [ ] byte ) ( int , error ) {
2014-02-26 21:33:33 +11:00
lenByteOffset := offset
2016-05-15 02:56:20 +10:00
if offset >= len ( msg ) || len ( s ) > len ( tmp ) {
2014-02-26 21:33:33 +11:00
return offset , ErrBuf
}
offset ++
bs := tmp [ : len ( s ) ]
copy ( bs , s )
for i := 0 ; i < len ( bs ) ; i ++ {
if len ( msg ) <= offset {
return offset , ErrBuf
}
if bs [ i ] == '\\' {
i ++
if i == len ( bs ) {
break
}
// check for \DDD
if i + 2 < len ( bs ) && isDigit ( bs [ i ] ) && isDigit ( bs [ i + 1 ] ) && isDigit ( bs [ i + 2 ] ) {
msg [ offset ] = dddToByte ( bs [ i : ] )
i += 2
} else {
msg [ offset ] = bs [ i ]
}
} else {
msg [ offset ] = bs [ i ]
}
offset ++
}
l := offset - lenByteOffset - 1
if l > 255 {
2014-04-08 09:09:26 +10:00
return offset , & Error { err : "string exceeded 255 bytes in txt" }
2014-02-26 21:33:33 +11:00
}
msg [ lenByteOffset ] = byte ( l )
return offset , nil
}
2015-06-18 09:06:31 +10:00
func packOctetString ( s string , msg [ ] byte , offset int , tmp [ ] byte ) ( int , error ) {
2016-05-15 02:56:20 +10:00
if offset >= len ( msg ) || len ( s ) > len ( tmp ) {
2015-06-18 09:06:31 +10:00
return offset , ErrBuf
}
bs := tmp [ : len ( s ) ]
copy ( bs , s )
for i := 0 ; i < len ( bs ) ; i ++ {
if len ( msg ) <= offset {
return offset , ErrBuf
}
if bs [ i ] == '\\' {
i ++
if i == len ( bs ) {
break
}
// check for \DDD
if i + 2 < len ( bs ) && isDigit ( bs [ i ] ) && isDigit ( bs [ i + 1 ] ) && isDigit ( bs [ i + 2 ] ) {
msg [ offset ] = dddToByte ( bs [ i : ] )
i += 2
} else {
msg [ offset ] = bs [ i ]
}
} else {
msg [ offset ] = bs [ i ]
}
offset ++
}
return offset , nil
}
2015-08-05 09:18:02 +10:00
func unpackTxt ( msg [ ] byte , off0 int ) ( ss [ ] string , off int , err error ) {
off = off0
2014-02-26 21:33:33 +11:00
var s string
2015-08-05 09:18:02 +10:00
for off < len ( msg ) && err == nil {
s , off , err = unpackTxtString ( msg , off )
2014-02-26 21:33:33 +11:00
if err == nil {
ss = append ( ss , s )
}
}
2015-08-05 09:18:02 +10:00
return
2014-02-26 21:33:33 +11:00
}
2014-03-02 09:25:24 +11:00
func unpackTxtString ( msg [ ] byte , offset int ) ( string , int , error ) {
2014-04-24 06:06:17 +10:00
if offset + 1 > len ( msg ) {
2014-04-08 09:09:26 +10:00
return "" , offset , & Error { err : "overflow unpacking txt" }
}
2014-02-26 21:33:33 +11:00
l := int ( msg [ offset ] )
if offset + l + 1 > len ( msg ) {
2014-04-08 09:09:26 +10:00
return "" , offset , & Error { err : "overflow unpacking txt" }
2014-02-26 21:33:33 +11:00
}
s := make ( [ ] byte , 0 , l )
for _ , b := range msg [ offset + 1 : offset + 1 + l ] {
switch b {
case '"' , '\\' :
s = append ( s , '\\' , b )
default :
if b < 32 || b > 127 { // unprintable
2014-11-10 03:09:49 +11:00
var buf [ 3 ] byte
bufs := strconv . AppendInt ( buf [ : 0 ] , int64 ( b ) , 10 )
s = append ( s , '\\' )
for i := 0 ; i < 3 - len ( bufs ) ; i ++ {
s = append ( s , '0' )
}
for _ , r := range bufs {
s = append ( s , r )
}
} else {
s = append ( s , b )
2014-02-26 21:33:33 +11:00
}
}
}
offset += 1 + l
return string ( s ) , offset , nil
}
// Helpers for dealing with escaped bytes
func isDigit ( b byte ) bool { return b >= '0' && b <= '9' }
func dddToByte ( s [ ] byte ) byte {
return byte ( ( s [ 0 ] - '0' ) * 100 + ( s [ 1 ] - '0' ) * 10 + ( s [ 2 ] - '0' ) )
}
2014-12-06 06:15:17 +11:00
// Helper function for packing and unpacking
2014-12-06 07:16:13 +11:00
func intToBytes ( i * big . Int , length int ) [ ] byte {
buf := i . Bytes ( )
if len ( buf ) < length {
b := make ( [ ] byte , length )
copy ( b [ length - len ( buf ) : ] , buf )
return b
}
return buf
}
2014-02-06 08:47:26 +11:00
// PackRR packs a resource record rr into msg[off:].
2014-02-06 08:38:12 +11:00
// See PackDomainName for documentation about the compression.
2012-10-10 06:17:54 +11:00
func PackRR ( rr RR , msg [ ] byte , off int , compression map [ string ] int , compress bool ) ( off1 int , err error ) {
2011-01-02 05:51:25 +11:00
if rr == nil {
2013-06-20 16:27:28 +10:00
return len ( msg ) , & Error { err : "nil rr" }
2011-01-02 05:51:25 +11:00
}
2010-12-31 03:15:59 +11:00
2016-06-13 03:31:50 +10:00
off1 , err = rr . pack ( msg , off , compression , compress )
2012-10-10 06:17:54 +11:00
if err != nil {
return len ( msg ) , err
2012-09-01 04:57:16 +10:00
}
2016-06-14 04:44:38 +10:00
// TODO(miek): Not sure if this is needed? If removed we can remove rawmsg.go as well.
2014-04-29 15:03:01 +10:00
if rawSetRdlength ( msg , off , off1 ) {
return off1 , nil
}
return off , ErrRdata
2010-08-04 07:57:59 +10:00
}
2014-02-06 08:38:12 +11:00
// UnpackRR unpacks msg[off:] into an RR.
2012-10-10 06:17:54 +11:00
func UnpackRR ( msg [ ] byte , off int ) ( rr RR , off1 int , err error ) {
2016-05-15 02:56:20 +10:00
h , off , msg , err := unpackHeader ( msg , off )
if err != nil {
2012-10-10 06:17:54 +11:00
return nil , len ( msg ) , err
2010-08-04 07:57:59 +10:00
}
2018-03-15 20:09:45 +11:00
return UnpackRRWithHeader ( h , msg , off )
}
// UnpackRRWithHeader unpacks the record type specific payload given an existing
// RR_Header.
func UnpackRRWithHeader ( h RR_Header , msg [ ] byte , off int ) ( rr RR , off1 int , err error ) {
2010-08-04 07:57:59 +10:00
end := off + int ( h . Rdlength )
2016-05-15 02:56:20 +10:00
2016-06-13 03:31:50 +10:00
if fn , known := typeToUnpack [ h . Rrtype ] ; ! known {
rr , off , err = unpackRFC3597 ( h , msg , off )
} else {
rr , off , err = fn ( h , msg , off )
2016-05-15 02:56:20 +10:00
}
2010-08-04 07:57:59 +10:00
if off != end {
2013-06-20 16:27:28 +10:00
return & h , end , & Error { err : "bad rdlength" }
2010-08-04 07:57:59 +10:00
}
2012-10-10 06:17:54 +11:00
return rr , off , err
2010-08-04 07:57:59 +10:00
}
2015-11-02 07:46:57 +11:00
// unpackRRslice unpacks msg[off:] into an []RR.
// If we cannot unpack the whole array, then it will return nil
func unpackRRslice ( l int , msg [ ] byte , off int ) ( dst1 [ ] RR , off1 int , err error ) {
var r RR
2017-12-21 21:24:07 +11:00
// Don't pre-allocate, l may be under attacker control
var dst [ ] RR
2015-11-02 07:46:57 +11:00
for i := 0 ; i < l ; i ++ {
off1 := off
r , off , err = UnpackRR ( msg , off )
if err != nil {
off = len ( msg )
break
}
// If offset does not increase anymore, l is a lie
if off1 == off {
l = i
break
}
dst = append ( dst , r )
}
if err != nil && off == len ( msg ) {
dst = nil
}
return dst , off , err
}
2012-08-22 01:36:58 +10:00
// Convert a MsgHdr to a string, with dig-like headers:
2012-01-17 07:44:49 +11:00
//
2011-02-22 01:57:15 +11:00
//;; opcode: QUERY, status: NOERROR, id: 48404
2012-01-17 07:44:49 +11:00
//
2010-08-04 07:57:59 +10:00
//;; flags: qr aa rd ra;
func ( h * MsgHdr ) String ( ) string {
2010-10-07 17:45:21 +11:00
if h == nil {
return "<nil> MsgHdr"
}
2012-12-02 19:29:54 +11:00
s := ";; opcode: " + OpcodeToString [ h . Opcode ]
s += ", status: " + RcodeToString [ h . Rcode ]
2010-12-19 06:31:26 +11:00
s += ", id: " + strconv . Itoa ( int ( h . Id ) ) + "\n"
2010-08-04 07:57:59 +10:00
2011-01-19 05:19:42 +11:00
s += ";; flags:"
2010-12-22 00:41:48 +11:00
if h . Response {
2011-01-19 05:19:42 +11:00
s += " qr"
2010-12-22 00:41:48 +11:00
}
2010-12-19 06:31:26 +11:00
if h . Authoritative {
2011-01-19 05:19:42 +11:00
s += " aa"
2010-08-04 07:57:59 +10:00
}
2010-12-19 06:31:26 +11:00
if h . Truncated {
2011-01-19 05:19:42 +11:00
s += " tc"
2010-08-04 07:57:59 +10:00
}
2010-12-31 00:13:28 +11:00
if h . RecursionDesired {
2011-01-19 05:19:42 +11:00
s += " rd"
2010-08-04 07:57:59 +10:00
}
2010-12-31 00:13:28 +11:00
if h . RecursionAvailable {
2011-01-19 05:19:42 +11:00
s += " ra"
2010-08-04 07:57:59 +10:00
}
2010-12-31 00:13:28 +11:00
if h . Zero { // Hmm
2011-01-19 05:19:42 +11:00
s += " z"
2010-12-22 00:41:48 +11:00
}
2010-12-31 00:13:28 +11:00
if h . AuthenticatedData {
2011-01-19 05:19:42 +11:00
s += " ad"
2010-12-22 00:41:48 +11:00
}
2010-12-31 00:13:28 +11:00
if h . CheckingDisabled {
2011-01-19 05:19:42 +11:00
s += " cd"
2010-12-22 00:41:48 +11:00
}
2010-08-04 07:57:59 +10:00
s += ";"
return s
}
2012-01-27 08:52:29 +11:00
// Pack packs a Msg: it is converted to to wire format.
// If the dns.Compress is true the message will be in compressed wire format.
2012-10-10 06:17:54 +11:00
func ( dns * Msg ) Pack ( ) ( msg [ ] byte , err error ) {
2014-01-11 02:46:24 +11:00
return dns . PackBuffer ( nil )
}
2018-05-16 17:53:51 +10:00
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
2014-01-11 02:46:24 +11:00
func ( dns * Msg ) PackBuffer ( buf [ ] byte ) ( msg [ ] byte , err error ) {
2018-05-16 16:20:13 +10:00
var compression map [ string ] int
2012-10-10 07:06:35 +11:00
if dns . Compress {
2018-05-16 17:53:51 +10:00
compression = make ( map [ string ] int ) // Compression pointer mappings.
2012-10-10 07:06:35 +11:00
}
2018-05-16 16:20:13 +10:00
return dns . packBufferWithCompressionMap ( buf , compression )
}
2018-05-16 17:53:51 +10:00
// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
2018-05-16 16:20:13 +10:00
func ( dns * Msg ) packBufferWithCompressionMap ( buf [ ] byte , compression map [ string ] int ) ( msg [ ] byte , err error ) {
// We use a similar function in tsig.go's stripTsig.
2018-05-16 17:53:51 +10:00
var dh Header
2010-08-04 07:57:59 +10:00
2014-09-26 21:16:48 +10:00
if dns . Rcode < 0 || dns . Rcode > 0xFFF {
2014-10-09 01:35:23 +11:00
return nil , ErrRcode
2014-09-26 21:16:48 +10:00
}
if dns . Rcode > 0xF {
// Regular RCODE field is 4 bits
opt := dns . IsEdns0 ( )
if opt == nil {
2014-10-09 01:31:28 +11:00
return nil , ErrExtendedRcode
2014-09-26 21:16:48 +10:00
}
2014-10-09 01:31:28 +11:00
opt . SetExtendedRcode ( uint8 ( dns . Rcode >> 4 ) )
2014-09-26 21:16:48 +10:00
}
2010-08-04 07:57:59 +10:00
// Convert convenient Msg into wire-like Header.
2010-12-19 06:31:26 +11:00
dh . Id = dns . Id
2018-05-13 17:36:02 +10:00
dh . Bits = uint16 ( dns . Opcode ) << 11 | uint16 ( dns . Rcode & 0xF )
2010-12-22 00:41:48 +11:00
if dns . Response {
dh . Bits |= _QR
2010-08-04 07:57:59 +10:00
}
2010-12-22 00:41:48 +11:00
if dns . Authoritative {
dh . Bits |= _AA
2010-08-04 07:57:59 +10:00
}
2010-12-19 06:31:26 +11:00
if dns . Truncated {
2010-08-04 07:57:59 +10:00
dh . Bits |= _TC
}
2010-12-31 00:13:28 +11:00
if dns . RecursionDesired {
2010-12-22 00:41:48 +11:00
dh . Bits |= _RD
2010-08-04 07:57:59 +10:00
}
2010-12-31 00:13:28 +11:00
if dns . RecursionAvailable {
2010-12-22 00:41:48 +11:00
dh . Bits |= _RA
}
2010-12-31 00:13:28 +11:00
if dns . Zero {
2010-12-22 00:41:48 +11:00
dh . Bits |= _Z
}
2010-12-31 00:13:28 +11:00
if dns . AuthenticatedData {
2010-12-22 00:41:48 +11:00
dh . Bits |= _AD
}
2010-12-31 00:13:28 +11:00
if dns . CheckingDisabled {
2010-12-22 00:41:48 +11:00
dh . Bits |= _CD
2010-08-04 07:57:59 +10:00
}
// Prepare variable sized arrays.
2010-08-09 20:40:31 +10:00
question := dns . Question
answer := dns . Answer
ns := dns . Ns
extra := dns . Extra
2010-08-04 07:57:59 +10:00
dh . Qdcount = uint16 ( len ( question ) )
dh . Ancount = uint16 ( len ( answer ) )
dh . Nscount = uint16 ( len ( ns ) )
dh . Arcount = uint16 ( len ( extra ) )
2014-02-10 23:23:53 +11:00
// We need the uncompressed length here, because we first pack it and then compress it.
2014-01-11 02:46:24 +11:00
msg = buf
2017-02-17 23:10:30 +11:00
uncompressedLen := compressedLen ( dns , false )
if packLen := uncompressedLen + 1 ; len ( msg ) < packLen {
2014-01-12 21:21:23 +11:00
msg = make ( [ ] byte , packLen )
2014-01-11 02:46:24 +11:00
}
2010-08-04 07:57:59 +10:00
// Pack it in: header and then the pieces.
off := 0
2016-05-15 02:56:20 +10:00
off , err = dh . pack ( msg , off , compression , dns . Compress )
2013-03-19 04:56:48 +11:00
if err != nil {
return nil , err
}
2010-08-04 07:57:59 +10:00
for i := 0 ; i < len ( question ) ; i ++ {
2016-05-15 02:56:20 +10:00
off , err = question [ i ] . pack ( msg , off , compression , dns . Compress )
2012-10-10 06:17:54 +11:00
if err != nil {
return nil , err
}
2010-08-04 07:57:59 +10:00
}
for i := 0 ; i < len ( answer ) ; i ++ {
2012-10-10 06:17:54 +11:00
off , err = PackRR ( answer [ i ] , msg , off , compression , dns . Compress )
if err != nil {
return nil , err
}
2010-08-04 07:57:59 +10:00
}
for i := 0 ; i < len ( ns ) ; i ++ {
2012-10-10 06:17:54 +11:00
off , err = PackRR ( ns [ i ] , msg , off , compression , dns . Compress )
if err != nil {
return nil , err
}
2010-08-04 07:57:59 +10:00
}
for i := 0 ; i < len ( extra ) ; i ++ {
2012-10-10 06:17:54 +11:00
off , err = PackRR ( extra [ i ] , msg , off , compression , dns . Compress )
if err != nil {
return nil , err
}
2010-08-04 07:57:59 +10:00
}
2012-10-10 06:17:54 +11:00
return msg [ : off ] , nil
2010-08-04 07:57:59 +10:00
}
2012-01-27 08:52:29 +11:00
// Unpack unpacks a binary message to a Msg structure.
2012-10-10 06:17:54 +11:00
func ( dns * Msg ) Unpack ( msg [ ] byte ) ( err error ) {
2016-05-15 02:56:20 +10:00
var (
dh Header
off int
)
if dh , off , err = unpackMsgHdr ( msg , off ) ; err != nil {
2012-10-10 06:17:54 +11:00
return err
2010-08-04 07:57:59 +10:00
}
2016-05-15 02:56:20 +10:00
2010-12-19 06:31:26 +11:00
dns . Id = dh . Id
2018-08-17 02:05:27 +10:00
dns . Response = dh . Bits & _QR != 0
2010-12-19 06:31:26 +11:00
dns . Opcode = int ( dh . Bits >> 11 ) & 0xF
2018-08-17 02:05:27 +10:00
dns . Authoritative = dh . Bits & _AA != 0
dns . Truncated = dh . Bits & _TC != 0
dns . RecursionDesired = dh . Bits & _RD != 0
dns . RecursionAvailable = dh . Bits & _RA != 0
dns . Zero = dh . Bits & _Z != 0
dns . AuthenticatedData = dh . Bits & _AD != 0
dns . CheckingDisabled = dh . Bits & _CD != 0
2010-12-19 06:31:26 +11:00
dns . Rcode = int ( dh . Bits & 0xF )
2010-08-04 07:57:59 +10:00
2017-12-20 21:51:13 +11:00
// If we are at the end of the message we should return *just* the
// header. This can still be useful to the caller. 9.9.9.9 sends these
// when responding with REFUSED for instance.
2017-01-30 21:53:01 +11:00
if off == len ( msg ) {
2017-12-20 21:51:13 +11:00
// reset sections before returning
dns . Question , dns . Answer , dns . Ns , dns . Extra = nil , nil , nil , nil
return nil
2017-01-30 21:53:01 +11:00
}
2017-12-21 21:24:07 +11:00
// Qdcount, Ancount, Nscount, Arcount can't be trusted, as they are
// attacker controlled. This means we can't use them to pre-allocate
// slices.
dns . Question = nil
2015-07-28 06:48:46 +10:00
for i := 0 ; i < int ( dh . Qdcount ) ; i ++ {
off1 := off
2016-05-15 02:56:20 +10:00
var q Question
q , off , err = unpackQuestion ( msg , off )
2012-10-10 06:17:54 +11:00
if err != nil {
2015-11-02 07:46:57 +11:00
// Even if Truncated is set, we only will set ErrTruncated if we
// actually got the questions
2012-10-10 06:17:54 +11:00
return err
}
2015-07-28 06:48:46 +10:00
if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
dh . Qdcount = uint16 ( i )
break
}
dns . Question = append ( dns . Question , q )
2014-02-06 08:47:26 +11:00
}
2015-07-28 06:48:46 +10:00
2015-11-02 07:46:57 +11:00
dns . Answer , off , err = unpackRRslice ( int ( dh . Ancount ) , msg , off )
// The header counts might have been wrong so we need to update it
dh . Ancount = uint16 ( len ( dns . Answer ) )
if err == nil {
dns . Ns , off , err = unpackRRslice ( int ( dh . Nscount ) , msg , off )
2010-08-04 07:57:59 +10:00
}
2015-11-02 07:46:57 +11:00
// The header counts might have been wrong so we need to update it
dh . Nscount = uint16 ( len ( dns . Ns ) )
if err == nil {
dns . Extra , off , err = unpackRRslice ( int ( dh . Arcount ) , msg , off )
2010-08-04 07:57:59 +10:00
}
2015-11-02 07:46:57 +11:00
// The header counts might have been wrong so we need to update it
dh . Arcount = uint16 ( len ( dns . Extra ) )
2016-05-15 02:56:20 +10:00
2010-08-04 07:57:59 +10:00
if off != len ( msg ) {
2013-06-20 16:25:29 +10:00
// TODO(miek) make this an error?
2013-06-29 18:50:43 +10:00
// use PackOpt to let people tell how detailed the error reporting should be?
2013-06-20 16:25:29 +10:00
// println("dns: extra bytes in dns packet", off, "<", len(msg))
2015-11-02 07:46:57 +11:00
} else if dns . Truncated {
// Whether we ran into a an error or not, we want to return that it
// was truncated
err = ErrTruncated
2010-08-04 07:57:59 +10:00
}
2015-11-02 07:46:57 +11:00
return err
2010-08-04 07:57:59 +10:00
}
2011-01-27 19:29:11 +11:00
// Convert a complete message to a string with dig-like output.
2010-08-04 07:57:59 +10:00
func ( dns * Msg ) String ( ) string {
2010-10-07 17:46:46 +11:00
if dns == nil {
return "<nil> MsgHdr"
}
2010-08-04 07:57:59 +10:00
s := dns . MsgHdr . String ( ) + " "
2010-08-09 20:40:31 +10:00
s += "QUERY: " + strconv . Itoa ( len ( dns . Question ) ) + ", "
s += "ANSWER: " + strconv . Itoa ( len ( dns . Answer ) ) + ", "
s += "AUTHORITY: " + strconv . Itoa ( len ( dns . Ns ) ) + ", "
s += "ADDITIONAL: " + strconv . Itoa ( len ( dns . Extra ) ) + "\n"
if len ( dns . Question ) > 0 {
2010-08-04 07:57:59 +10:00
s += "\n;; QUESTION SECTION:\n"
2010-08-09 20:40:31 +10:00
for i := 0 ; i < len ( dns . Question ) ; i ++ {
2011-03-24 19:24:49 +11:00
s += dns . Question [ i ] . String ( ) + "\n"
2010-08-04 07:57:59 +10:00
}
}
2010-08-09 20:40:31 +10:00
if len ( dns . Answer ) > 0 {
2010-08-04 07:57:59 +10:00
s += "\n;; ANSWER SECTION:\n"
2010-08-09 20:40:31 +10:00
for i := 0 ; i < len ( dns . Answer ) ; i ++ {
2011-03-16 02:18:13 +11:00
if dns . Answer [ i ] != nil {
s += dns . Answer [ i ] . String ( ) + "\n"
}
2010-08-04 07:57:59 +10:00
}
}
2010-08-09 20:40:31 +10:00
if len ( dns . Ns ) > 0 {
2010-08-04 07:57:59 +10:00
s += "\n;; AUTHORITY SECTION:\n"
2010-08-09 20:40:31 +10:00
for i := 0 ; i < len ( dns . Ns ) ; i ++ {
2011-03-16 02:18:13 +11:00
if dns . Ns [ i ] != nil {
s += dns . Ns [ i ] . String ( ) + "\n"
}
2010-08-04 07:57:59 +10:00
}
}
2010-08-09 20:40:31 +10:00
if len ( dns . Extra ) > 0 {
2010-08-04 07:57:59 +10:00
s += "\n;; ADDITIONAL SECTION:\n"
2010-08-09 20:40:31 +10:00
for i := 0 ; i < len ( dns . Extra ) ; i ++ {
2011-03-16 02:18:13 +11:00
if dns . Extra [ i ] != nil {
s += dns . Extra [ i ] . String ( ) + "\n"
}
2010-08-04 07:57:59 +10:00
}
}
return s
}
2011-01-02 03:42:13 +11:00
2013-06-27 07:18:09 +10:00
// Len returns the message length when in (un)compressed wire format.
2013-06-27 19:07:01 +10:00
// If dns.Compress is true compression it is taken into account. Len()
// is provided to be a faster way to get the size of the resulting packet,
// than packing it, measuring the size and discarding the buffer.
2017-02-17 23:10:30 +11:00
func ( dns * Msg ) Len ( ) int { return compressedLen ( dns , dns . Compress ) }
2018-05-16 16:20:13 +10:00
func compressedLenWithCompressionMap ( dns * Msg , compression map [ string ] int ) int {
l := 12 // Message header is always 12 bytes
for _ , r := range dns . Question {
compressionLenHelper ( compression , r . Name , l )
l += r . len ( )
}
l += compressionLenSlice ( l , compression , dns . Answer )
l += compressionLenSlice ( l , compression , dns . Ns )
l += compressionLenSlice ( l , compression , dns . Extra )
return l
}
2017-02-17 23:10:30 +11:00
// compressedLen returns the message length when in compressed wire format
// when compress is true, otherwise the uncompressed length is returned.
func compressedLen ( dns * Msg , compress bool ) int {
2014-02-12 23:59:42 +11:00
// We always return one more than needed.
2017-10-14 02:21:12 +11:00
if compress {
compression := map [ string ] int { }
2018-05-16 16:20:13 +10:00
return compressedLenWithCompressionMap ( dns , compression )
2018-04-01 18:45:32 +10:00
}
2018-05-16 16:20:13 +10:00
l := 12 // Message header is always 12 bytes
2018-04-01 18:45:32 +10:00
for _ , r := range dns . Question {
l += r . len ( )
}
for _ , r := range dns . Answer {
if r != nil {
2017-10-14 02:21:12 +11:00
l += r . len ( )
2016-05-15 02:56:20 +10:00
}
2018-04-01 18:45:32 +10:00
}
for _ , r := range dns . Ns {
if r != nil {
l += r . len ( )
2017-10-14 02:21:12 +11:00
}
2018-04-01 18:45:32 +10:00
}
for _ , r := range dns . Extra {
if r != nil {
l += r . len ( )
2012-08-27 04:46:24 +10:00
}
2012-01-10 20:43:28 +11:00
}
2018-04-01 18:45:32 +10:00
2017-10-14 02:21:12 +11:00
return l
}
2018-05-16 16:20:13 +10:00
func compressionLenSlice ( lenp int , c map [ string ] int , rs [ ] RR ) int {
initLen := lenp
2017-10-14 02:21:12 +11:00
for _ , r := range rs {
if r == nil {
2016-05-15 02:56:20 +10:00
continue
}
2018-05-16 16:20:13 +10:00
// TmpLen is to track len of record at 14bits boudaries
tmpLen := lenp
2018-04-01 18:45:32 +10:00
2018-05-16 16:20:13 +10:00
x := r . len ( )
// track this length, and the global length in len, while taking compression into account for both.
k , ok , _ := compressionLenSearch ( c , r . Header ( ) . Name )
2017-10-14 02:21:12 +11:00
if ok {
2018-05-16 16:20:13 +10:00
// Size of x is reduced by k, but we add 1 since k includes the '.' and label descriptor take 2 bytes
// so, basically x:= x - k - 1 + 2
x += 1 - k
2017-10-14 02:21:12 +11:00
}
2018-04-01 18:45:32 +10:00
2018-05-16 16:20:13 +10:00
tmpLen += compressionLenHelper ( c , r . Header ( ) . Name , tmpLen )
k , ok , _ = compressionLenSearchType ( c , r )
2017-10-14 02:21:12 +11:00
if ok {
2018-05-16 16:20:13 +10:00
x += 1 - k
2018-04-01 18:45:32 +10:00
}
2018-05-16 16:20:13 +10:00
lenp += x
tmpLen = lenp
tmpLen += compressionLenHelperType ( c , r , tmpLen )
2018-04-01 18:45:32 +10:00
2012-01-10 20:43:28 +11:00
}
2018-05-16 16:20:13 +10:00
return lenp - initLen
2012-01-10 20:43:28 +11:00
}
2018-05-16 16:20:13 +10:00
// Put the parts of the name in the compression map, return the size in bytes added in payload
func compressionLenHelper ( c map [ string ] int , s string , currentLen int ) int {
if currentLen > maxCompressionOffset {
// We won't be able to add any label that could be re-used later anyway
return 0
}
if _ , ok := c [ s ] ; ok {
return 0
}
initLen := currentLen
2012-08-27 04:46:24 +10:00
pref := ""
2018-05-16 16:20:13 +10:00
prev := s
2014-01-26 13:09:28 +11:00
lbs := Split ( s )
2018-05-16 16:20:13 +10:00
for j := 0 ; j < len ( lbs ) ; j ++ {
2014-01-26 13:09:28 +11:00
pref = s [ lbs [ j ] : ]
2018-05-16 16:20:13 +10:00
currentLen += len ( prev ) - len ( pref )
prev = pref
2014-02-12 10:01:47 +11:00
if _ , ok := c [ pref ] ; ! ok {
2018-05-16 16:20:13 +10:00
// If first byte label is within the first 14bits, it might be re-used later
if currentLen < maxCompressionOffset {
c [ pref ] = currentLen
}
} else {
added := currentLen - initLen
if j > 0 {
// We added a new PTR
added += 2
}
return added
2014-02-12 10:01:47 +11:00
}
2012-08-27 04:46:24 +10:00
}
2018-05-16 16:20:13 +10:00
return currentLen - initLen
2012-08-27 04:46:24 +10:00
}
2014-02-12 10:01:47 +11:00
// Look for each part in the compression map and returns its length,
2014-02-10 23:43:09 +11:00
// keep on searching so we get the longest match.
2018-05-16 16:20:13 +10:00
// Will return the size of compression found, whether a match has been
// found and the size of record if added in payload
func compressionLenSearch ( c map [ string ] int , s string ) ( int , bool , int ) {
2013-06-27 19:07:01 +10:00
off := 0
end := false
2014-08-22 18:46:24 +10:00
if s == "" { // don't bork on bogus data
2018-05-16 16:20:13 +10:00
return 0 , false , 0
2014-08-22 18:46:24 +10:00
}
2018-05-16 16:20:13 +10:00
fullSize := 0
2013-06-27 19:07:01 +10:00
for {
if _ , ok := c [ s [ off : ] ] ; ok {
2018-05-16 16:20:13 +10:00
return len ( s [ off : ] ) , true , fullSize + off
2013-06-27 19:07:01 +10:00
}
2014-02-12 10:01:47 +11:00
if end {
break
}
2018-05-16 16:20:13 +10:00
// Each label descriptor takes 2 bytes, add it
fullSize += 2
2013-06-27 19:07:01 +10:00
off , end = NextLabel ( s , off )
}
2018-05-16 16:20:13 +10:00
return 0 , false , fullSize + len ( s )
2013-06-27 19:07:01 +10:00
}
2014-02-12 10:01:47 +11:00
// Copy returns a new RR which is a deep-copy of r.
2016-06-14 04:44:38 +10:00
func Copy ( r RR ) RR { r1 := r . copy ( ) ; return r1 }
2014-02-12 10:01:47 +11:00
2016-03-18 01:07:51 +11:00
// Len returns the length (in octets) of the uncompressed RR in wire format.
2016-06-14 04:44:38 +10:00
func Len ( r RR ) int { return r . len ( ) }
2016-03-18 01:07:51 +11:00
2014-02-12 10:01:47 +11:00
// Copy returns a new *Msg which is a deep-copy of dns.
2016-06-14 04:44:38 +10:00
func ( dns * Msg ) Copy ( ) * Msg { return dns . CopyTo ( new ( Msg ) ) }
2015-02-24 18:11:31 +11:00
// CopyTo copies the contents to the provided message using a deep-copy and returns the copy.
func ( dns * Msg ) CopyTo ( r1 * Msg ) * Msg {
2014-02-12 10:01:47 +11:00
r1 . MsgHdr = dns . MsgHdr
r1 . Compress = dns . Compress
2014-03-01 02:03:21 +11:00
if len ( dns . Question ) > 0 {
r1 . Question = make ( [ ] Question , len ( dns . Question ) )
copy ( r1 . Question , dns . Question ) // TODO(miek): Question is an immutable value, ok to do a shallow-copy
}
2014-02-12 10:01:47 +11:00
2015-02-06 00:07:07 +11:00
rrArr := make ( [ ] RR , len ( dns . Answer ) + len ( dns . Ns ) + len ( dns . Extra ) )
var rri int
2014-03-01 02:03:21 +11:00
if len ( dns . Answer ) > 0 {
2015-02-06 00:07:07 +11:00
rrbegin := rri
2014-03-01 02:03:21 +11:00
for i := 0 ; i < len ( dns . Answer ) ; i ++ {
2015-02-06 00:07:07 +11:00
rrArr [ rri ] = dns . Answer [ i ] . copy ( )
rri ++
2014-03-01 02:03:21 +11:00
}
2015-02-06 00:07:07 +11:00
r1 . Answer = rrArr [ rrbegin : rri : rri ]
2014-02-12 10:01:47 +11:00
}
2014-03-01 02:03:21 +11:00
if len ( dns . Ns ) > 0 {
2015-02-06 00:07:07 +11:00
rrbegin := rri
2014-03-01 02:03:21 +11:00
for i := 0 ; i < len ( dns . Ns ) ; i ++ {
2015-02-06 00:07:07 +11:00
rrArr [ rri ] = dns . Ns [ i ] . copy ( )
rri ++
2014-03-01 02:03:21 +11:00
}
2015-02-06 00:07:07 +11:00
r1 . Ns = rrArr [ rrbegin : rri : rri ]
2014-02-12 10:01:47 +11:00
}
2014-03-01 02:03:21 +11:00
if len ( dns . Extra ) > 0 {
2015-02-06 00:07:07 +11:00
rrbegin := rri
2014-03-01 02:03:21 +11:00
for i := 0 ; i < len ( dns . Extra ) ; i ++ {
2015-02-06 00:07:07 +11:00
rrArr [ rri ] = dns . Extra [ i ] . copy ( )
rri ++
2014-03-01 02:03:21 +11:00
}
2015-02-06 00:07:07 +11:00
r1 . Extra = rrArr [ rrbegin : rri : rri ]
2014-02-12 10:01:47 +11:00
}
2014-03-01 02:03:21 +11:00
2014-02-12 10:01:47 +11:00
return r1
}
2016-05-15 02:56:20 +10:00
func ( q * Question ) pack ( msg [ ] byte , off int , compression map [ string ] int , compress bool ) ( int , error ) {
off , err := PackDomainName ( q . Name , msg , off , compression , compress )
if err != nil {
return off , err
}
off , err = packUint16 ( q . Qtype , msg , off )
if err != nil {
return off , err
}
off , err = packUint16 ( q . Qclass , msg , off )
if err != nil {
return off , err
}
return off , nil
}
func unpackQuestion ( msg [ ] byte , off int ) ( Question , int , error ) {
var (
q Question
err error
)
q . Name , off , err = UnpackDomainName ( msg , off )
if err != nil {
return q , off , err
}
if off == len ( msg ) {
return q , off , nil
}
q . Qtype , off , err = unpackUint16 ( msg , off )
if err != nil {
return q , off , err
}
if off == len ( msg ) {
return q , off , nil
}
q . Qclass , off , err = unpackUint16 ( msg , off )
if off == len ( msg ) {
return q , off , nil
}
return q , off , err
}
func ( dh * Header ) pack ( msg [ ] byte , off int , compression map [ string ] int , compress bool ) ( int , error ) {
off , err := packUint16 ( dh . Id , msg , off )
if err != nil {
return off , err
}
off , err = packUint16 ( dh . Bits , msg , off )
if err != nil {
return off , err
}
off , err = packUint16 ( dh . Qdcount , msg , off )
if err != nil {
return off , err
}
off , err = packUint16 ( dh . Ancount , msg , off )
if err != nil {
return off , err
}
off , err = packUint16 ( dh . Nscount , msg , off )
if err != nil {
return off , err
}
off , err = packUint16 ( dh . Arcount , msg , off )
return off , err
}
func unpackMsgHdr ( msg [ ] byte , off int ) ( Header , int , error ) {
var (
dh Header
err error
)
dh . Id , off , err = unpackUint16 ( msg , off )
if err != nil {
return dh , off , err
}
dh . Bits , off , err = unpackUint16 ( msg , off )
if err != nil {
return dh , off , err
}
dh . Qdcount , off , err = unpackUint16 ( msg , off )
if err != nil {
return dh , off , err
}
dh . Ancount , off , err = unpackUint16 ( msg , off )
if err != nil {
return dh , off , err
}
dh . Nscount , off , err = unpackUint16 ( msg , off )
if err != nil {
return dh , off , err
}
dh . Arcount , off , err = unpackUint16 ( msg , off )
return dh , off , err
}