From f0154aa0c26b0b2afa5546bdf94ecd789e82d0b7 Mon Sep 17 00:00:00 2001 From: Miek Gieben Date: Tue, 15 May 2012 12:24:57 +0200 Subject: [PATCH] Fix and test rfc 1982 arithmetic --- dns.go | 2 +- parse_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ types.go | 18 +++++++++++------- 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/dns.go b/dns.go index a956b281..250c9b38 100644 --- a/dns.go +++ b/dns.go @@ -82,7 +82,7 @@ import ( ) const ( - Year68 = 1 << 32 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. + Year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits. DefaultMsgSize = 4096 // Standard default for larger than 512 packets. UDPMsgSize = 512 // Default buffer size for servers receiving UDP packets. MaxMsgSize = 65536 // Largest possible DNS packet. diff --git a/parse_test.go b/parse_test.go index b6ad21ac..a9400efe 100644 --- a/parse_test.go +++ b/parse_test.go @@ -509,3 +509,47 @@ func TestLineNumberError2(t *testing.T) { // fmt.Printf("%s\n", err.Error()) } } + +// Test if the calculations are correct +func TestRfc1982(t *testing.T) { + // If the current time and the timestamp are more than 68 years apart + // it means the date has wrapped. 0 is 1970 + + // fall in the current 68 year span + strtests := []string{"20120525134203", "19700101000000", "20380119031408"} + for _, v := range strtests { + if x, _ := DateToTime(v); v != TimeToDate(x) { + t.Logf("1982 arithmetic string failure %s (%s:%d)", v, TimeToDate(x), x) + t.Fail() + } + } + + inttests := map[uint32]string{0: "19700101000000", + 1 << 31: "20380119031408", + 1<<32 - 1: "21060207062815", + } + for i, v := range inttests { + if TimeToDate(i) != v { + t.Logf("1982 arithmetic int failure %d:%s (%s)", i, v, TimeToDate(i)) + t.Fail() + } + } + + // Future tests, these dates get parsed to a date within the current 136 year span + future := map[string]string{"22680119031408": "20631123173144", + "19010101121212": "20370206184028", + "19210101121212": "20570206184028", + "19500101121212": "20860206184028", + "19700101000000": "19700101000000", + "19690101000000": "21050207062816", + "29210101121212": "21040522212236", + } + for from, to := range future { + x, _ := DateToTime(from) + y := TimeToDate(x) + if y != to { + t.Logf("1982 arithmetic future failure %s:%s (%s)", from, to, y) + t.Fail() + } + } +} diff --git a/types.go b/types.go index eb234df4..0304e216 100644 --- a/types.go +++ b/types.go @@ -1100,23 +1100,27 @@ func (rr *RR_HIP) Len() int { // string representation used when printing the record. // It takes serial arithmetic (RFC 1982) into account. [TODO] func TimeToDate(t uint32) string { - // utc := time.Now().UTC().Unix() - // mod := (int64(t) - utc) / Year68 - ti := time.Unix(int64(t), 0).UTC() + mod := ( (int64(t) - time.Now().Unix()) / Year68 ) - 1 + if mod < 0 { + mod = 0 + } + ti := time.Unix(int64(t) - (mod * Year68), 0).UTC() return ti.Format("20060102150405") } // DateToTime translates the RRSIG's incep. and expir. times from // string values like "20110403154150" to an 32 bit integer. -// It takes serial arithmetic (RFC 1982) into account. [TODO] +// It takes serial arithmetic (RFC 1982) into account. func DateToTime(s string) (uint32, error) { t, e := time.Parse("20060102150405", s) if e != nil { return 0, e } - mod := t.Unix() / Year68 - ti := uint32(t.Unix() - (mod * Year68)) - return ti, nil + mod := ( t.Unix() / Year68 ) - 1 + if mod < 0 { + mod = 0 + } + return uint32(t.Unix() - (mod * Year68)), nil } // saltString converts a NSECX salt to uppercase and