From bacfa5a80cd3b37713a6ce371dd74262e59c0fdc Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 10 Jan 2012 10:43:28 +0100 Subject: [PATCH] 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 --- dns.go | 17 +++-- edns.go | 4 ++ msg.go | 27 ++++++++ types.go | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 227 insertions(+), 20 deletions(-) diff --git a/dns.go b/dns.go index 4f3e3ed4..18149dbb 100644 --- a/dns.go +++ b/dns.go @@ -91,6 +91,7 @@ func (e *Error) Error() string { type RR interface { Header() *RR_Header String() string + Len() int } // An RRset is a slice of RRs. @@ -212,15 +213,21 @@ func (h *RR_Header) String() string { 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) { if len(pattern) == 0 { return } - if len(zone) == 0 { - zone = "." - } - pattern = Fqdn(pattern) - zone = Fqdn(zone) + if len(zone) == 0 { + zone = "." + } + pattern = Fqdn(pattern) + zone = Fqdn(zone) i := 0 for { ok = pattern[len(pattern)-1-i] == zone[len(zone)-1-i] diff --git a/edns.go b/edns.go index f003167d..6f6cecf0 100644 --- a/edns.go +++ b/edns.go @@ -75,6 +75,10 @@ func (rr *RR_OPT) String() string { return s } +func (rr *RR_OPT) Len() int { + return rr.Hdr.Len() + len(rr.Option) // TODO: to small/large? +} + // TODO(mg) // Get the EDNS version (always 0 currently). func (rr *RR_OPT) Version() uint8 { diff --git a/msg.go b/msg.go index 4cf67e02..3f0e6a05 100644 --- a/msg.go +++ b/msg.go @@ -1094,6 +1094,33 @@ func (dns *Msg) String() string { 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 // message id. The random provided should be good enough. func Id() uint16 { diff --git a/types.go b/types.go index 35ac3203..3a0f8da8 100644 --- a/types.go +++ b/types.go @@ -136,11 +136,11 @@ type Question struct { func (q *Question) String() (s string) { // prefix with ; (as in dig) - if len(q.Name) == 0 { - s = ";.\t" // root label - } else { - s = ";" + q.Name + "\t" - } + if len(q.Name) == 0 { + s = ";.\t" // root label + } else { + s = ";" + q.Name + "\t" + } s = s + Class_str[q.Qclass] + "\t" if _, ok := Rr_str[q.Qtype]; ok { s += " " + Rr_str[q.Qtype] @@ -150,6 +150,11 @@ func (q *Question) String() (s string) { return s } +func (q *Question) Len() int { + l, _ := IsDomainName(q.Name) + return int(l) + 4 +} + type RR_ANY struct { Hdr RR_Header // Does not have any rdata @@ -163,6 +168,10 @@ func (rr *RR_ANY) String() string { return rr.Hdr.String() } +func (rr *RR_ANY) Len() int { + return rr.Hdr.Len() +} + type RR_CNAME struct { Hdr RR_Header Cname string "domain-name" @@ -176,6 +185,11 @@ func (rr *RR_CNAME) String() string { 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 { Hdr RR_Header Cpu string @@ -190,6 +204,10 @@ func (rr *RR_HINFO) String() string { 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 { Hdr RR_Header Mb string "domain-name" @@ -203,6 +221,11 @@ func (rr *RR_MB) String() string { 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 { Hdr RR_Header Mg string "domain-name" @@ -216,6 +239,11 @@ func (rr *RR_MG) String() string { 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 { Hdr RR_Header Rmail string "domain-name" @@ -230,6 +258,12 @@ func (rr *RR_MINFO) String() string { 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 { Hdr RR_Header Mr string "domain-name" @@ -243,6 +277,11 @@ func (rr *RR_MR) String() string { 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 { Hdr RR_Header Pref uint16 @@ -257,6 +296,11 @@ func (rr *RR_MX) String() string { 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 { Hdr RR_Header Ns string "domain-name" @@ -270,6 +314,11 @@ func (rr *RR_NS) String() string { 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 { Hdr RR_Header Ptr string "domain-name" @@ -283,6 +332,11 @@ func (rr *RR_PTR) String() string { 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 { Hdr RR_Header Ns string "domain-name" @@ -307,6 +361,12 @@ func (rr *RR_SOA) String() string { " " + 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 { Hdr RR_Header Txt string "txt" @@ -320,6 +380,10 @@ func (rr *RR_TXT) String() string { 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 { Hdr RR_Header Priority uint16 @@ -339,6 +403,11 @@ func (rr *RR_SRV) String() string { 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 { Hdr RR_Header Order uint16 @@ -363,6 +432,10 @@ func (rr *RR_NAPTR) String() string { rr.Replacement } +func (rr *RR_NAPTR) Len() int { + return rr.Hdr.Len() + 0 +} + // See RFC 4398. type RR_CERT struct { Hdr RR_Header @@ -383,6 +456,10 @@ func (rr *RR_CERT) String() string { " " + rr.Certificate } +func (rr *RR_CERT) Len() int { + return rr.Hdr.Len() + 0 +} + // See RFC 2672. type RR_DNAME struct { Hdr RR_Header @@ -397,6 +474,11 @@ func (rr *RR_DNAME) String() string { 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 { Hdr RR_Header A net.IP "A" @@ -410,6 +492,10 @@ func (rr *RR_A) String() 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 { Hdr RR_Header AAAA net.IP "AAAA" @@ -423,6 +509,10 @@ func (rr *RR_AAAA) String() string { return rr.Hdr.String() + rr.AAAA.String() } +func (rr *RR_AAAA) Len() int { + return rr.Hdr.Len() + 16 +} + type RR_LOC struct { Hdr RR_Header Version uint8 @@ -443,6 +533,10 @@ func (rr *RR_LOC) String() string { return rr.Hdr.String() + "TODO" } +func (rr *RR_LOC) Len() int { + return rr.Hdr.Len() + 0 +} + type RR_RRSIG struct { Hdr RR_Header TypeCovered uint16 @@ -472,6 +566,12 @@ func (rr *RR_RRSIG) String() string { " " + 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 { Hdr RR_Header NextDomain string "domain-name" @@ -494,6 +594,12 @@ func (rr *RR_NSEC) String() string { 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 { Hdr RR_Header KeyTag uint16 @@ -513,6 +619,10 @@ func (rr *RR_DS) String() string { " " + strings.ToUpper(rr.Digest) } +func (rr *RR_DS) Len() int { + return rr.Hdr.Len() + 4 + len(rr.Digest)/2 +} + type RR_DLV struct { Hdr RR_Header KeyTag uint16 @@ -532,6 +642,10 @@ func (rr *RR_DLV) String() string { " " + strings.ToUpper(rr.Digest) } +func (rr *RR_DLV) Len() int { + return rr.Hdr.Len() + 4 + len(rr.Digest)/2 +} + type RR_KX struct { Hdr RR_Header Preference uint16 @@ -547,6 +661,10 @@ func (rr *RR_KX) String() string { " " + rr.Exchanger } +func (rr *RR_KX) Len() int { + return 0 +} + type RR_TA struct { Hdr RR_Header KeyTag uint16 @@ -566,6 +684,10 @@ func (rr *RR_TA) String() string { " " + strings.ToUpper(rr.Digest) } +func (rr *RR_TA) Len() int { + return rr.Hdr.Len() + 4 + len(rr.Digest)/2 +} + type RR_TALINK struct { Hdr RR_Header PreviousName string "domain" @@ -581,6 +703,12 @@ func (rr *RR_TALINK) String() string { " " + 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 { Hdr RR_Header Algorithm uint8 @@ -598,6 +726,10 @@ func (rr *RR_SSHFP) String() string { " " + strings.ToUpper(rr.FingerPrint) } +func (rr *RR_SSHFP) Len() int { + return rr.Hdr.Len() + 2 + len(rr.FingerPrint)/2 +} + type RR_DNSKEY struct { Hdr RR_Header Flags uint16 @@ -617,6 +749,10 @@ func (rr *RR_DNSKEY) String() string { " " + rr.PublicKey } +func (rr *RR_DNSKEY) Len() int { + return rr.Hdr.Len() + 4 + len(rr.PublicKey) // todo: base64 +} + type RR_NSEC3 struct { Hdr RR_Header Hash uint8 @@ -650,6 +786,11 @@ func (rr *RR_NSEC3) String() string { 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 { Hdr RR_Header Hash uint8 @@ -672,13 +813,8 @@ func (rr *RR_NSEC3PARAM) String() string { return s } -// 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) +func (rr *RR_NSEC3PARAM) Len() int { + return rr.Hdr.Len() + 0 } // See RFC 4408. @@ -695,6 +831,10 @@ func (rr *RR_SPF) String() string { return rr.Hdr.String() + "\"" + rr.Txt + "\"" } +func (rr *RR_SPF) Len() int { + return rr.Hdr.Len() + 0 +} + type RR_TKEY struct { Hdr RR_Header Algorithm string "domain-name" @@ -717,6 +857,10 @@ func (rr *RR_TKEY) String() string { return "" } +func (rr *RR_TKEY) Len() int { + return rr.Hdr.Len() + 0 +} + // Unknown RR representation type RR_RFC3597 struct { Hdr RR_Header @@ -733,6 +877,10 @@ func (rr *RR_RFC3597) String() string { return s } +func (rr *RR_RFC3597) Len() int { + return rr.Hdr.Len() + len(rr.Rdata)/2 +} + type RR_URI struct { Hdr RR_Header Priority uint16 @@ -750,6 +898,10 @@ func (rr *RR_URI) String() string { " " + rr.Target } +func (rr *RR_URI) Len() int { + return rr.Hdr.Len() + 0 +} + type RR_DHCID struct { Hdr RR_Header Digest string "base64" @@ -763,6 +915,10 @@ func (rr *RR_DHCID) String() string { return rr.Hdr.String() + rr.Digest } +func (rr *RR_DHCID) Len() int { + return rr.Hdr.Len() + 0 +} + // RFC 2845. type RR_TSIG struct { Hdr RR_Header @@ -795,11 +951,15 @@ func (rr *RR_TSIG) String() string { " " + 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. // Taking into account serial arithmetic (RFC 1982) [TODO] func timeToDate(t uint32) string { -// utc := time.Now().UTC().Unix() -// mod := (int64(t) - utc) / Year68 + // utc := time.Now().UTC().Unix() + // mod := (int64(t) - utc) / Year68 ti := time.Unix(int64(t), 0).UTC() return ti.Format("20060102150405") } @@ -813,7 +973,7 @@ func dateToTime(s string) (uint32, error) { return 0, e } mod := t.Unix() / Year68 - ti := uint32(t.Unix() - (mod * Year68)) + ti := uint32(t.Unix() - (mod * Year68)) 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. var rr_mk = map[uint16]func() RR{ TypeCNAME: func() RR { return new(RR_CNAME) },