diff --git a/parse_test.go b/parse_test.go index 0771afb8..b0d02f45 100644 --- a/parse_test.go +++ b/parse_test.go @@ -548,6 +548,9 @@ a.example.com. IN A 127.0.0.1 8db7._openpgpkey.example.com. IN OPENPGPKEY mQCNAzIG $ORIGIN a.example.com. test IN A 127.0.0.1 + IN SSHFP 1 2 ( + BC6533CDC95A79078A39A56EA7635984ED655318ADA9 + B6159E30723665DA95BB ) $ORIGIN b.example.com. test IN CNAME test.a.example.com. ` @@ -904,8 +907,9 @@ func TestILNP(t *testing.T) { func TestNsapGposEidNimloc(t *testing.T) { dt := map[string]string{ - "foo.bar.com. IN NSAP 21 47000580ffff000000321099991111222233334444": "foo.bar.com.\t3600\tIN\tNSAP\t21 47000580ffff000000321099991111222233334444", - "host.school.de IN NSAP 17 39276f3100111100002222333344449876": "host.school.de.\t3600\tIN\tNSAP\t17 39276f3100111100002222333344449876", + "foo.bar.com. IN NSAP 21 47000580ffff000000321099991111222233334444": "foo.bar.com.\t3600\tIN\tNSAP\t0x47000580ffff000000321099991111222233334444", + "foo.bar.com. IN NSAP 0x47000580ffff000000321099991111222233334444": "foo.bar.com.\t3600\tIN\tNSAP\t0x47000580ffff000000321099991111222233334444", + "host.school.de IN NSAP 17 39276f3100111100002222333344449876": "host.school.de.\t3600\tIN\tNSAP\t0x39276f3100111100002222333344449876", "444433332222111199990123000000ff. NSAP-PTR foo.bar.com.": "444433332222111199990123000000ff.\t3600\tIN\tNSAP-PTR\tfoo.bar.com.", "lillee. IN GPOS -32.6882 116.8652 10.0": "lillee.\t3600\tIN\tGPOS\t-32.6882 116.8652 10.0", "hinault. IN GPOS -22.6882 116.8652 250.0": "hinault.\t3600\tIN\tGPOS\t-22.6882 116.8652 250.0", @@ -1397,10 +1401,6 @@ func TestParseTLSA(t *testing.T) { t.Error("failed to parse RR: ", err) continue } - if rr == nil { - t.Errorf("TLSA RR `%s` not parsed!", o) - continue - } if rr.String() != o { t.Errorf("`%s' should be equal to\n`%s', but is `%s'", o, o, rr.String()) } else { @@ -1408,3 +1408,50 @@ func TestParseTLSA(t *testing.T) { } } } + +func TestParseSSHFP(t *testing.T) { + lt := []string{ + "test.example.org.\t300\tSSHFP\t1 2 (\n" + + "\t\t\t\t\tBC6533CDC95A79078A39A56EA7635984ED655318ADA9\n" + + "\t\t\t\t\tB6159E30723665DA95BB )", + "test.example.org.\t300\tSSHFP\t1 2 ( BC6533CDC 95A79078A39A56EA7635984ED655318AD A9B6159E3072366 5DA95BB )", + } + result := "test.example.org.\t300\tIN\tSSHFP\t1 2 BC6533CDC95A79078A39A56EA7635984ED655318ADA9B6159E30723665DA95BB" + for _, o := range lt { + rr, err := NewRR(o) + if err != nil { + t.Error("failed to parse RR: ", err) + continue + } + if rr.String() != result { + t.Errorf("`%s' should be equal to\n\n`%s', but is \n`%s'", o, result, rr.String()) + } else { + t.Logf("RR is OK: `%s'", rr.String()) + } + } +} + +func TestParseHINFO(t *testing.T) { + dt := map[string]string{ + "example.net. HINFO A B": "example.net. 3600 IN HINFO \"A\" \"B\"", + "example.net. HINFO \"A\" \"B\"": "example.net. 3600 IN HINFO \"A\" \"B\"", + "example.net. HINFO A B C D E F": "example.net. 3600 IN HINFO \"A\" \"B C D E F\"", + "example.net. HINFO AB": "example.net. 3600 IN HINFO \"AB\" \"\"", + // "example.net. HINFO PC-Intel-700mhz \"Redhat Linux 7.1\"": "example.net. 3600 IN HINFO \"PC-Intel-700mhz\" \"Redhat Linux 7.1\"", + // This one is recommended in Pro Bind book http://www.zytrax.com/books/dns/ch8/hinfo.html + // but effectively, even Bind would replace it to correctly formed text when you AXFR + // TODO: remove this set of comments or figure support for quoted/unquoted combinations in endingToTxtSlice function + } + for i, o := range dt { + rr, err := NewRR(i) + if err != nil { + t.Error("failed to parse RR: ", err) + continue + } + if rr.String() != o { + t.Errorf("`%s' should be equal to\n`%s', but is `%s'", i, o, rr.String()) + } else { + t.Logf("RR is OK: `%s'", rr.String()) + } + } +} diff --git a/types.go b/types.go index 40cc0a4f..bd95fd9a 100644 --- a/types.go +++ b/types.go @@ -255,8 +255,10 @@ type HINFO struct { func (rr *HINFO) Header() *RR_Header { return &rr.Hdr } func (rr *HINFO) copy() RR { return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os} } -func (rr *HINFO) String() string { return rr.Hdr.String() + rr.Cpu + " " + rr.Os } -func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) } +func (rr *HINFO) String() string { + return rr.Hdr.String() + sprintTxt([]string{rr.Cpu, rr.Os}) +} +func (rr *HINFO) len() int { return rr.Hdr.len() + len(rr.Cpu) + len(rr.Os) } type MB struct { Hdr RR_Header @@ -1146,14 +1148,13 @@ func (rr *RKEY) String() string { } type NSAP struct { - Hdr RR_Header - Length uint8 - Nsap string + Hdr RR_Header + Nsap string } func (rr *NSAP) Header() *RR_Header { return &rr.Hdr } -func (rr *NSAP) copy() RR { return &NSAP{*rr.Hdr.copyHeader(), rr.Length, rr.Nsap} } -func (rr *NSAP) String() string { return rr.Hdr.String() + strconv.Itoa(int(rr.Length)) + " " + rr.Nsap } +func (rr *NSAP) copy() RR { return &NSAP{*rr.Hdr.copyHeader(), rr.Nsap} } +func (rr *NSAP) String() string { return rr.Hdr.String() + "0x" + rr.Nsap } func (rr *NSAP) len() int { return rr.Hdr.len() + 1 + len(rr.Nsap) + 1 } type NSAPPTR struct { diff --git a/zscan_rr.go b/zscan_rr.go index 05e914a1..e5ca2615 100644 --- a/zscan_rr.go +++ b/zscan_rr.go @@ -345,11 +345,24 @@ func setHINFO(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(HINFO) rr.Hdr = h - l := <-c - rr.Cpu = l.token - <-c // zBlank - l = <-c // zString - rr.Os = l.token + chunks, e, c1 := endingToTxtSlice(c, "bad HINFO Fields", f) + if e != nil { + return nil, e, c1 + } + + if ln := len(chunks); ln == 0 { + return rr, nil, "" + } else if ln == 1 { + // Can we split it? + if out := strings.Fields(chunks[0]); len(out) > 1 { + chunks = out + } else { + chunks = append(chunks, "") + } + } + + rr.Cpu = chunks[0] + rr.Os = strings.Join(chunks[1:], " ") return rr, nil, "" } @@ -1450,9 +1463,9 @@ func setWKS(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { case zString: if k, err = net.LookupPort(proto, l.token); err != nil { if i, e := strconv.Atoi(l.token); e != nil { // If a number use that - rr.BitMap = append(rr.BitMap, uint16(i)) - } else { return nil, &ParseError{f, "bad WKS BitMap", l}, "" + } else { + rr.BitMap = append(rr.BitMap, uint16(i)) } } rr.BitMap = append(rr.BitMap, uint16(k)) @@ -1485,8 +1498,11 @@ func setSSHFP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { } rr.Type = uint8(i) <-c // zBlank - l = <-c - rr.FingerPrint = l.token + s, e1, c1 := endingToString(c, "bad SSHFP Fingerprint", f) + if e1 != nil { + return nil, e1, c1 + } + rr.FingerPrint = s return rr, nil, "" } @@ -1606,21 +1622,28 @@ func setNIMLOC(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { func setNSAP(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { rr := new(NSAP) rr.Hdr = h - l := <-c - if l.length == 0 { - return rr, nil, l.comment - } - i, e := strconv.Atoi(l.token) - if e != nil { - return nil, &ParseError{f, "bad NSAP Length", l}, "" - } - rr.Length = uint8(i) - <-c // zBlank - s, e1, c1 := endingToString(c, "bad NSAP Nsap", f) - if e != nil { + chunks, e1, c1 := endingToTxtSlice(c, "bad NSAP Nsap", f) + if e1 != nil { return nil, e1, c1 } - rr.Nsap = s + // data would come as one string or multiple... Just to ignore possible + // variety let's merge things back together and split to actual "words" + s := strings.Fields(strings.Join(chunks, " ")) + if len(s) == 0 { + return rr, nil, c1 + } + if len(s[0]) >= 2 && s[0][0:2] == "0x" || s[0][0:2] == "0X" { + // although RFC only suggests 0x there is no clarification that X is not allowed + rr.Nsap = strings.Join(s, "")[2:] + } else { + // since we do not know what to do with this data, and, we would not use original length + // in formatting, it's moot to check correctness of the length + _, err := strconv.Atoi(s[0]) + if err != nil { + return nil, &ParseError{f, "bad NSAP Length", lex{token: s[0]}}, "" + } + rr.Nsap = strings.Join(s[1:], "") + } return rr, nil, c1 } @@ -2166,7 +2189,7 @@ var typeToparserFunc = map[uint16]parserFunc{ TypeEUI64: parserFunc{setEUI64, false}, TypeGID: parserFunc{setGID, false}, TypeGPOS: parserFunc{setGPOS, false}, - TypeHINFO: parserFunc{setHINFO, false}, + TypeHINFO: parserFunc{setHINFO, true}, TypeHIP: parserFunc{setHIP, true}, TypeIPSECKEY: parserFunc{setIPSECKEY, true}, TypeKX: parserFunc{setKX, false}, @@ -2202,7 +2225,7 @@ var typeToparserFunc = map[uint16]parserFunc{ TypeSOA: parserFunc{setSOA, false}, TypeSPF: parserFunc{setSPF, true}, TypeSRV: parserFunc{setSRV, false}, - TypeSSHFP: parserFunc{setSSHFP, false}, + TypeSSHFP: parserFunc{setSSHFP, true}, TypeTALINK: parserFunc{setTALINK, false}, TypeTA: parserFunc{setTA, true}, TypeTLSA: parserFunc{setTLSA, true},