A Len() to RR interface

This isn't yet finished, but it helps in asserting the amount of
space to alloc when packing a message
This commit is contained in:
Miek Gieben 2012-01-10 10:43:28 +01:00
parent 973c5f3e1a
commit bacfa5a80c
4 changed files with 227 additions and 20 deletions

17
dns.go
View File

@ -91,6 +91,7 @@ func (e *Error) Error() string {
type RR interface { type RR interface {
Header() *RR_Header Header() *RR_Header
String() string String() string
Len() int
} }
// An RRset is a slice of RRs. // An RRset is a slice of RRs.
@ -212,15 +213,21 @@ func (h *RR_Header) String() string {
return s return s
} }
func (h *RR_Header) Len() int {
l, _ := IsDomainName(h.Name)
l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
return int(l)
}
func zoneMatch(pattern, zone string) (ok bool) { func zoneMatch(pattern, zone string) (ok bool) {
if len(pattern) == 0 { if len(pattern) == 0 {
return return
} }
if len(zone) == 0 { if len(zone) == 0 {
zone = "." zone = "."
} }
pattern = Fqdn(pattern) pattern = Fqdn(pattern)
zone = Fqdn(zone) zone = Fqdn(zone)
i := 0 i := 0
for { for {
ok = pattern[len(pattern)-1-i] == zone[len(zone)-1-i] ok = pattern[len(pattern)-1-i] == zone[len(zone)-1-i]

View File

@ -75,6 +75,10 @@ func (rr *RR_OPT) String() string {
return s return s
} }
func (rr *RR_OPT) Len() int {
return rr.Hdr.Len() + len(rr.Option) // TODO: to small/large?
}
// TODO(mg) // TODO(mg)
// Get the EDNS version (always 0 currently). // Get the EDNS version (always 0 currently).
func (rr *RR_OPT) Version() uint8 { func (rr *RR_OPT) Version() uint8 {

27
msg.go
View File

@ -1094,6 +1094,33 @@ func (dns *Msg) String() string {
return s return s
} }
// Len return the message length (in uncompressed wirefmt).
func (dns *Msg) Len() int {
// Message header is always 12 bytes
l := 12
if len(dns.Question) > 0 {
for i := 0; i < len(dns.Question); i++ {
l += dns.Question[i].Len()
}
}
if len(dns.Answer) > 0 {
for i := 0; i < len(dns.Answer); i++ {
l += dns.Answer[i].Len()
}
}
if len(dns.Ns) > 0 {
for i := 0; i < len(dns.Ns); i++ {
l += dns.Ns[i].Len()
}
}
if len(dns.Extra) > 0 {
for i := 0; i < len(dns.Extra); i++ {
l += dns.Extra[i].Len()
}
}
return l
}
// Id return a 16 bits random number to be used as a // Id return a 16 bits random number to be used as a
// message id. The random provided should be good enough. // message id. The random provided should be good enough.
func Id() uint16 { func Id() uint16 {

199
types.go
View File

@ -136,11 +136,11 @@ type Question struct {
func (q *Question) String() (s string) { func (q *Question) String() (s string) {
// prefix with ; (as in dig) // prefix with ; (as in dig)
if len(q.Name) == 0 { if len(q.Name) == 0 {
s = ";.\t" // root label s = ";.\t" // root label
} else { } else {
s = ";" + q.Name + "\t" s = ";" + q.Name + "\t"
} }
s = s + Class_str[q.Qclass] + "\t" s = s + Class_str[q.Qclass] + "\t"
if _, ok := Rr_str[q.Qtype]; ok { if _, ok := Rr_str[q.Qtype]; ok {
s += " " + Rr_str[q.Qtype] s += " " + Rr_str[q.Qtype]
@ -150,6 +150,11 @@ func (q *Question) String() (s string) {
return s return s
} }
func (q *Question) Len() int {
l, _ := IsDomainName(q.Name)
return int(l) + 4
}
type RR_ANY struct { type RR_ANY struct {
Hdr RR_Header Hdr RR_Header
// Does not have any rdata // Does not have any rdata
@ -163,6 +168,10 @@ func (rr *RR_ANY) String() string {
return rr.Hdr.String() return rr.Hdr.String()
} }
func (rr *RR_ANY) Len() int {
return rr.Hdr.Len()
}
type RR_CNAME struct { type RR_CNAME struct {
Hdr RR_Header Hdr RR_Header
Cname string "domain-name" Cname string "domain-name"
@ -176,6 +185,11 @@ func (rr *RR_CNAME) String() string {
return rr.Hdr.String() + rr.Cname return rr.Hdr.String() + rr.Cname
} }
func (rr *RR_CNAME) Len() int {
l, _ := IsDomainName(rr.Cname)
return rr.Hdr.Len() + int(l)
}
type RR_HINFO struct { type RR_HINFO struct {
Hdr RR_Header Hdr RR_Header
Cpu string Cpu string
@ -190,6 +204,10 @@ func (rr *RR_HINFO) String() string {
return rr.Hdr.String() + rr.Cpu + " " + rr.Os return rr.Hdr.String() + rr.Cpu + " " + rr.Os
} }
func (rr *RR_HINFO) Len() int {
return rr.Hdr.Len() + len(rr.Cpu) + len(rr.Os)
}
type RR_MB struct { type RR_MB struct {
Hdr RR_Header Hdr RR_Header
Mb string "domain-name" Mb string "domain-name"
@ -203,6 +221,11 @@ func (rr *RR_MB) String() string {
return rr.Hdr.String() + rr.Mb return rr.Hdr.String() + rr.Mb
} }
func (rr *RR_MB) Len() int {
l, _ := IsDomainName(rr.Mb)
return rr.Hdr.Len() + int(l)
}
type RR_MG struct { type RR_MG struct {
Hdr RR_Header Hdr RR_Header
Mg string "domain-name" Mg string "domain-name"
@ -216,6 +239,11 @@ func (rr *RR_MG) String() string {
return rr.Hdr.String() + rr.Mg return rr.Hdr.String() + rr.Mg
} }
func (rr *RR_MG) Len() int {
l, _ := IsDomainName(rr.Mg)
return rr.Hdr.Len() + int(l)
}
type RR_MINFO struct { type RR_MINFO struct {
Hdr RR_Header Hdr RR_Header
Rmail string "domain-name" Rmail string "domain-name"
@ -230,6 +258,12 @@ func (rr *RR_MINFO) String() string {
return rr.Hdr.String() + rr.Rmail + " " + rr.Email return rr.Hdr.String() + rr.Rmail + " " + rr.Email
} }
func (rr *RR_MINFO) Len() int {
l, _ := IsDomainName(rr.Rmail)
n, _ := IsDomainName(rr.Email)
return rr.Hdr.Len() + int(l) + int(n)
}
type RR_MR struct { type RR_MR struct {
Hdr RR_Header Hdr RR_Header
Mr string "domain-name" Mr string "domain-name"
@ -243,6 +277,11 @@ func (rr *RR_MR) String() string {
return rr.Hdr.String() + rr.Mr return rr.Hdr.String() + rr.Mr
} }
func (rr *RR_MR) Len() int {
l, _ := IsDomainName(rr.Mr)
return rr.Hdr.Len() + int(l)
}
type RR_MX struct { type RR_MX struct {
Hdr RR_Header Hdr RR_Header
Pref uint16 Pref uint16
@ -257,6 +296,11 @@ func (rr *RR_MX) String() string {
return rr.Hdr.String() + strconv.Itoa(int(rr.Pref)) + " " + rr.Mx return rr.Hdr.String() + strconv.Itoa(int(rr.Pref)) + " " + rr.Mx
} }
func (rr *RR_MX) Len() int {
l, _ := IsDomainName(rr.Mx)
return rr.Hdr.Len() + int(l) + 2
}
type RR_NS struct { type RR_NS struct {
Hdr RR_Header Hdr RR_Header
Ns string "domain-name" Ns string "domain-name"
@ -270,6 +314,11 @@ func (rr *RR_NS) String() string {
return rr.Hdr.String() + rr.Ns return rr.Hdr.String() + rr.Ns
} }
func (rr *RR_NS) Len() int {
l, _ := IsDomainName(rr.Ns)
return rr.Hdr.Len() + int(l)
}
type RR_PTR struct { type RR_PTR struct {
Hdr RR_Header Hdr RR_Header
Ptr string "domain-name" Ptr string "domain-name"
@ -283,6 +332,11 @@ func (rr *RR_PTR) String() string {
return rr.Hdr.String() + rr.Ptr return rr.Hdr.String() + rr.Ptr
} }
func (rr *RR_PTR) Len() int {
l, _ := IsDomainName(rr.Ptr)
return rr.Hdr.Len() + int(l)
}
type RR_SOA struct { type RR_SOA struct {
Hdr RR_Header Hdr RR_Header
Ns string "domain-name" Ns string "domain-name"
@ -307,6 +361,12 @@ func (rr *RR_SOA) String() string {
" " + strconv.Itoa(int(rr.Minttl)) " " + strconv.Itoa(int(rr.Minttl))
} }
func (rr *RR_SOA) Len() int {
l, _ := IsDomainName(rr.Ns)
n, _ := IsDomainName(rr.Mbox)
return rr.Hdr.Len() + int(l) + int(n) + 20
}
type RR_TXT struct { type RR_TXT struct {
Hdr RR_Header Hdr RR_Header
Txt string "txt" Txt string "txt"
@ -320,6 +380,10 @@ func (rr *RR_TXT) String() string {
return rr.Hdr.String() + "\"" + rr.Txt + "\"" return rr.Hdr.String() + "\"" + rr.Txt + "\""
} }
func (rr *RR_TXT) Len() int {
return rr.Hdr.Len() + len(rr.Txt) // TODO: always works?
}
type RR_SRV struct { type RR_SRV struct {
Hdr RR_Header Hdr RR_Header
Priority uint16 Priority uint16
@ -339,6 +403,11 @@ func (rr *RR_SRV) String() string {
strconv.Itoa(int(rr.Port)) + " " + rr.Target strconv.Itoa(int(rr.Port)) + " " + rr.Target
} }
func (rr *RR_SRV) Len() int {
l, _ := IsDomainName(rr.Target)
return rr.Hdr.Len() + int(l) + 6
}
type RR_NAPTR struct { type RR_NAPTR struct {
Hdr RR_Header Hdr RR_Header
Order uint16 Order uint16
@ -363,6 +432,10 @@ func (rr *RR_NAPTR) String() string {
rr.Replacement rr.Replacement
} }
func (rr *RR_NAPTR) Len() int {
return rr.Hdr.Len() + 0
}
// See RFC 4398. // See RFC 4398.
type RR_CERT struct { type RR_CERT struct {
Hdr RR_Header Hdr RR_Header
@ -383,6 +456,10 @@ func (rr *RR_CERT) String() string {
" " + rr.Certificate " " + rr.Certificate
} }
func (rr *RR_CERT) Len() int {
return rr.Hdr.Len() + 0
}
// See RFC 2672. // See RFC 2672.
type RR_DNAME struct { type RR_DNAME struct {
Hdr RR_Header Hdr RR_Header
@ -397,6 +474,11 @@ func (rr *RR_DNAME) String() string {
return rr.Hdr.String() + rr.Target return rr.Hdr.String() + rr.Target
} }
func (rr *RR_DNAME) Len() int {
l, _ := IsDomainName(rr.Target)
return rr.Hdr.Len() + int(l)
}
type RR_A struct { type RR_A struct {
Hdr RR_Header Hdr RR_Header
A net.IP "A" A net.IP "A"
@ -410,6 +492,10 @@ func (rr *RR_A) String() string {
return rr.Hdr.String() + rr.A.String() return rr.Hdr.String() + rr.A.String()
} }
func (rr *RR_A) Len() int {
return rr.Hdr.Len() + 4 /// 4 bytes?
}
type RR_AAAA struct { type RR_AAAA struct {
Hdr RR_Header Hdr RR_Header
AAAA net.IP "AAAA" AAAA net.IP "AAAA"
@ -423,6 +509,10 @@ func (rr *RR_AAAA) String() string {
return rr.Hdr.String() + rr.AAAA.String() return rr.Hdr.String() + rr.AAAA.String()
} }
func (rr *RR_AAAA) Len() int {
return rr.Hdr.Len() + 16
}
type RR_LOC struct { type RR_LOC struct {
Hdr RR_Header Hdr RR_Header
Version uint8 Version uint8
@ -443,6 +533,10 @@ func (rr *RR_LOC) String() string {
return rr.Hdr.String() + "TODO" return rr.Hdr.String() + "TODO"
} }
func (rr *RR_LOC) Len() int {
return rr.Hdr.Len() + 0
}
type RR_RRSIG struct { type RR_RRSIG struct {
Hdr RR_Header Hdr RR_Header
TypeCovered uint16 TypeCovered uint16
@ -472,6 +566,12 @@ func (rr *RR_RRSIG) String() string {
" " + rr.Signature " " + rr.Signature
} }
func (rr *RR_RRSIG) Len() int {
l, _ := IsDomainName(rr.SignerName)
return rr.Hdr.Len() + int(l) + len(rr.Signature) + 18
// base64 string, wordt iets minder dus
}
type RR_NSEC struct { type RR_NSEC struct {
Hdr RR_Header Hdr RR_Header
NextDomain string "domain-name" NextDomain string "domain-name"
@ -494,6 +594,12 @@ func (rr *RR_NSEC) String() string {
return s return s
} }
func (rr *RR_NSEC) Len() int {
l, _ := IsDomainName(rr.NextDomain)
return rr.Hdr.Len() + int(l) + len(rr.TypeBitMap)
// This is also shorter due to the windowing
}
type RR_DS struct { type RR_DS struct {
Hdr RR_Header Hdr RR_Header
KeyTag uint16 KeyTag uint16
@ -513,6 +619,10 @@ func (rr *RR_DS) String() string {
" " + strings.ToUpper(rr.Digest) " " + strings.ToUpper(rr.Digest)
} }
func (rr *RR_DS) Len() int {
return rr.Hdr.Len() + 4 + len(rr.Digest)/2
}
type RR_DLV struct { type RR_DLV struct {
Hdr RR_Header Hdr RR_Header
KeyTag uint16 KeyTag uint16
@ -532,6 +642,10 @@ func (rr *RR_DLV) String() string {
" " + strings.ToUpper(rr.Digest) " " + strings.ToUpper(rr.Digest)
} }
func (rr *RR_DLV) Len() int {
return rr.Hdr.Len() + 4 + len(rr.Digest)/2
}
type RR_KX struct { type RR_KX struct {
Hdr RR_Header Hdr RR_Header
Preference uint16 Preference uint16
@ -547,6 +661,10 @@ func (rr *RR_KX) String() string {
" " + rr.Exchanger " " + rr.Exchanger
} }
func (rr *RR_KX) Len() int {
return 0
}
type RR_TA struct { type RR_TA struct {
Hdr RR_Header Hdr RR_Header
KeyTag uint16 KeyTag uint16
@ -566,6 +684,10 @@ func (rr *RR_TA) String() string {
" " + strings.ToUpper(rr.Digest) " " + strings.ToUpper(rr.Digest)
} }
func (rr *RR_TA) Len() int {
return rr.Hdr.Len() + 4 + len(rr.Digest)/2
}
type RR_TALINK struct { type RR_TALINK struct {
Hdr RR_Header Hdr RR_Header
PreviousName string "domain" PreviousName string "domain"
@ -581,6 +703,12 @@ func (rr *RR_TALINK) String() string {
" " + rr.PreviousName + " " + rr.NextName " " + rr.PreviousName + " " + rr.NextName
} }
func (rr *RR_TALINK) Len() int {
l, _ := IsDomainName(rr.PreviousName)
n, _ := IsDomainName(rr.NextName)
return rr.Hdr.Len() + int(l) + int(n)
}
type RR_SSHFP struct { type RR_SSHFP struct {
Hdr RR_Header Hdr RR_Header
Algorithm uint8 Algorithm uint8
@ -598,6 +726,10 @@ func (rr *RR_SSHFP) String() string {
" " + strings.ToUpper(rr.FingerPrint) " " + strings.ToUpper(rr.FingerPrint)
} }
func (rr *RR_SSHFP) Len() int {
return rr.Hdr.Len() + 2 + len(rr.FingerPrint)/2
}
type RR_DNSKEY struct { type RR_DNSKEY struct {
Hdr RR_Header Hdr RR_Header
Flags uint16 Flags uint16
@ -617,6 +749,10 @@ func (rr *RR_DNSKEY) String() string {
" " + rr.PublicKey " " + rr.PublicKey
} }
func (rr *RR_DNSKEY) Len() int {
return rr.Hdr.Len() + 4 + len(rr.PublicKey) // todo: base64
}
type RR_NSEC3 struct { type RR_NSEC3 struct {
Hdr RR_Header Hdr RR_Header
Hash uint8 Hash uint8
@ -650,6 +786,11 @@ func (rr *RR_NSEC3) String() string {
return s return s
} }
func (rr *RR_NSEC3) Len() int {
return rr.Hdr.Len() + 6 + len(rr.Salt)/2+1 + len(rr.NextDomain)+1 + len(rr.TypeBitMap)
// TODO: size-base32 and typebitmap
}
type RR_NSEC3PARAM struct { type RR_NSEC3PARAM struct {
Hdr RR_Header Hdr RR_Header
Hash uint8 Hash uint8
@ -672,13 +813,8 @@ func (rr *RR_NSEC3PARAM) String() string {
return s return s
} }
// saltString converts a NSECX salt to uppercase and func (rr *RR_NSEC3PARAM) Len() int {
// returns "-" when it is empty return rr.Hdr.Len() + 0
func saltString(s string) string {
if len(s) == 0 {
return "-"
}
return strings.ToUpper(s)
} }
// See RFC 4408. // See RFC 4408.
@ -695,6 +831,10 @@ func (rr *RR_SPF) String() string {
return rr.Hdr.String() + "\"" + rr.Txt + "\"" return rr.Hdr.String() + "\"" + rr.Txt + "\""
} }
func (rr *RR_SPF) Len() int {
return rr.Hdr.Len() + 0
}
type RR_TKEY struct { type RR_TKEY struct {
Hdr RR_Header Hdr RR_Header
Algorithm string "domain-name" Algorithm string "domain-name"
@ -717,6 +857,10 @@ func (rr *RR_TKEY) String() string {
return "" return ""
} }
func (rr *RR_TKEY) Len() int {
return rr.Hdr.Len() + 0
}
// Unknown RR representation // Unknown RR representation
type RR_RFC3597 struct { type RR_RFC3597 struct {
Hdr RR_Header Hdr RR_Header
@ -733,6 +877,10 @@ func (rr *RR_RFC3597) String() string {
return s return s
} }
func (rr *RR_RFC3597) Len() int {
return rr.Hdr.Len() + len(rr.Rdata)/2
}
type RR_URI struct { type RR_URI struct {
Hdr RR_Header Hdr RR_Header
Priority uint16 Priority uint16
@ -750,6 +898,10 @@ func (rr *RR_URI) String() string {
" " + rr.Target " " + rr.Target
} }
func (rr *RR_URI) Len() int {
return rr.Hdr.Len() + 0
}
type RR_DHCID struct { type RR_DHCID struct {
Hdr RR_Header Hdr RR_Header
Digest string "base64" Digest string "base64"
@ -763,6 +915,10 @@ func (rr *RR_DHCID) String() string {
return rr.Hdr.String() + rr.Digest return rr.Hdr.String() + rr.Digest
} }
func (rr *RR_DHCID) Len() int {
return rr.Hdr.Len() + 0
}
// RFC 2845. // RFC 2845.
type RR_TSIG struct { type RR_TSIG struct {
Hdr RR_Header Hdr RR_Header
@ -795,11 +951,15 @@ func (rr *RR_TSIG) String() string {
" " + rr.OtherData " " + rr.OtherData
} }
func (rr *RR_TSIG) Len() int {
return rr.Hdr.Len() + 0
}
// Translate the RRSIG's incep. and expir. time to the correct date. // Translate the RRSIG's incep. and expir. time to the correct date.
// Taking into account serial arithmetic (RFC 1982) [TODO] // Taking into account serial arithmetic (RFC 1982) [TODO]
func timeToDate(t uint32) string { func timeToDate(t uint32) string {
// utc := time.Now().UTC().Unix() // utc := time.Now().UTC().Unix()
// mod := (int64(t) - utc) / Year68 // mod := (int64(t) - utc) / Year68
ti := time.Unix(int64(t), 0).UTC() ti := time.Unix(int64(t), 0).UTC()
return ti.Format("20060102150405") return ti.Format("20060102150405")
} }
@ -813,7 +973,7 @@ func dateToTime(s string) (uint32, error) {
return 0, e return 0, e
} }
mod := t.Unix() / Year68 mod := t.Unix() / Year68
ti := uint32(t.Unix() - (mod * Year68)) ti := uint32(t.Unix() - (mod * Year68))
return ti, nil return ti, nil
} }
@ -828,6 +988,15 @@ func tsigTimeToDate(t uint64) string {
*/ */
} }
// saltString converts a NSECX salt to uppercase and
// returns "-" when it is empty
func saltString(s string) string {
if len(s) == 0 {
return "-"
}
return strings.ToUpper(s)
}
// Map of constructors for each RR wire type. // Map of constructors for each RR wire type.
var rr_mk = map[uint16]func() RR{ var rr_mk = map[uint16]func() RR{
TypeCNAME: func() RR { return new(RR_CNAME) }, TypeCNAME: func() RR { return new(RR_CNAME) },