diff --git a/keygen.go b/keygen.go index b71747e5..4e3a81df 100644 --- a/keygen.go +++ b/keygen.go @@ -114,7 +114,7 @@ func (r *RR_DNSKEY) PrivateKeyString(p PrivateKey) (s string) { func (k *RR_DNSKEY) Read(q io.Reader) os.Error { p := NewParser(q) - r, err := p.RR() + r, err := p.First() if err != nil { return err } diff --git a/types.go b/types.go index 098a96d6..246e0c8a 100644 --- a/types.go +++ b/types.go @@ -150,7 +150,7 @@ func (q *Question) String() string { // NewRRString returns the last RR contained in s. func NewRRString(s string) (RR, os.Error) { p := NewParser(strings.NewReader(s)) - return p.RR() + return p.First() } // NewRR returns a new RR with the hdr.Rrtype also set. diff --git a/types.rl b/types.rl index 2f4dda89..4a1fd743 100644 --- a/types.rl +++ b/types.rl @@ -1,5 +1,6 @@ %%{ machine z; + action setA { rdf := fields(data[mark:p], 1) rr := new(RR_A) @@ -7,9 +8,10 @@ rr.Hdr.Rrtype = TypeA rr.A = net.ParseIP(rdf[0]) if rr.A == nil { - return z, &ParseError{Error: "bad A", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad A", name: rdf[0], line: l} + return } - z.PushRR(rr) + zp.RR <- rr } action setAAAA { @@ -19,9 +21,10 @@ rr.Hdr.Rrtype = TypeAAAA rr.AAAA = net.ParseIP(rdf[0]) if rr.AAAA == nil { - return z, &ParseError{Error: "bad AAAA", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad AAAA", name: rdf[0], line: l} + return } - z.PushRR(rr) + zp.RR <- rr } action setNS { @@ -31,9 +34,10 @@ rr.Hdr.Rrtype = TypeNS rr.Ns = rdf[0] if ! IsDomainName(rdf[0]) { - return z, &ParseError{Error: "bad NS", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad NS", name: rdf[0], line: l} + return } - z.PushRR(rr) + zp.RR <- rr } action setMX { @@ -45,9 +49,10 @@ rr.Pref = uint16(i) rr.Mx = rdf[1] if err != nil { - return z, &ParseError{Error: "bad MX", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad MX", name: rdf[0], line: l} + return } - z.PushRR(rr) + zp.RR <- rr } action setCNAME { @@ -57,9 +62,10 @@ rr.Hdr.Rrtype = TypeCNAME rr.Cname = rdf[0] if ! IsDomainName(rdf[0]) { - return z, &ParseError{Error: "bad CNAME", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad CNAME", name: rdf[0], line: l} + return } - z.PushRR(rr) + zp.RR <- rr } action setSOA { @@ -74,14 +80,17 @@ rr.Ns = rdf[0] rr.Mbox = rdf[1] if ! IsDomainName(rdf[0]) { - return z, &ParseError{Error: "bad SOA", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad SOA", name: rdf[0], line: l} + return } if ! IsDomainName(rdf[1]) { - return z, &ParseError{Error: "bad SOA", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad SOA", name: rdf[1], line: l} + return } for j, s := range rdf[2:7] { if i, err = strconv.Atoui(s); err != nil { - return z, &ParseError{Error: "bad SOA", name: s, line: l} + zp.Err <- &ParseError{Error: "bad SOA", name: s, line: l} + return } switch j { case 0: rr.Serial = uint32(i) @@ -92,6 +101,7 @@ } } z.PushRR(rr) + zp.RR <- rr } action setDS { @@ -104,19 +114,22 @@ rr.Hdr = hdr rr.Hdr.Rrtype = TypeDS if i, e = strconv.Atoui(rdf[0]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[0], line: l} + return } rr.KeyTag = uint16(i) if i, e = strconv.Atoui(rdf[1]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[1], line: l} + return } rr.Algorithm = uint8(i) if i, e = strconv.Atoui(rdf[2]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[2], line: l} + return } rr.DigestType = uint8(i) rr.Digest = rdf[3] - z.PushRR(rr) + zp.RR <- rr } action setDLV { @@ -129,19 +142,22 @@ rr.Hdr = hdr rr.Hdr.Rrtype = TypeDLV if i, e = strconv.Atoui(rdf[0]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[0], line: l} + return } rr.KeyTag = uint16(i) if i, e = strconv.Atoui(rdf[1]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[1], line: l} + return } rr.Algorithm = uint8(i) if i, e = strconv.Atoui(rdf[2]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[2], line: l} + return } rr.DigestType = uint8(i) rr.Digest = rdf[3] - z.PushRR(rr) + zp.RR <- rr } action setTA { @@ -154,19 +170,22 @@ rr.Hdr = hdr rr.Hdr.Rrtype = TypeTA if i, e = strconv.Atoui(rdf[0]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[0], line: l} + return } rr.KeyTag = uint16(i) if i, e = strconv.Atoui(rdf[1]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[1], line: l} + return } rr.Algorithm = uint8(i) if i, e = strconv.Atoui(rdf[2]); e != nil { - return z, &ParseError{Error: "bad DS", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad DS", name: rdf[2], line: l} + return } rr.DigestType = uint8(i) rr.Digest = rdf[3] - z.PushRR(rr) + zp.RR <- rr } action setDNSKEY { @@ -180,19 +199,22 @@ rr.Hdr.Rrtype = TypeDNSKEY if i, e = strconv.Atoui(rdf[0]); e != nil { - return z, &ParseError{Error: "bad DNSKEY", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad DNSKEY", name: rdf[0], line: l} + return } rr.Flags = uint16(i) if i, e = strconv.Atoui(rdf[1]); e != nil { - return z, &ParseError{Error: "bad DNSKEY", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad DNSKEY", name: rdf[1], line: l} + return } rr.Protocol = uint8(i) if i, e = strconv.Atoui(rdf[2]); e != nil { - return z, &ParseError{Error: "bad DNSKEY", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad DNSKEY", name: rdf[2], line: l} + return } rr.Algorithm = uint8(i) rr.PublicKey = rdf[3] - z.PushRR(rr) + zp.RR <- rr } action setRRSIG { @@ -207,44 +229,52 @@ rr.Hdr.Rrtype = TypeRRSIG if _, ok := str_rr[strings.ToUpper(rdf[0])]; !ok { - return z, &ParseError{Error: "bad RRSIG", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[0], line: l} + return } rr.TypeCovered = str_rr[strings.ToUpper(rdf[0])] if i, err = strconv.Atoui(rdf[1]); err != nil { - return z, &ParseError{Error: "bad RRSIG", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[1], line: l} + return } rr.Algorithm = uint8(i) if i, err = strconv.Atoui(rdf[2]); err != nil { - return z, &ParseError{Error: "bad RRSIG", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[2], line: l} + return } rr.Labels = uint8(i) if i, err = strconv.Atoui(rdf[3]); err != nil { - return z, &ParseError{Error: "bad RRSIG", name: rdf[3], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[3], line: l} + return } rr.OrigTtl = uint32(i) if j, err = dateToTime(rdf[4]); err != nil { - return z, &ParseError{Error: "bad RRSIG", name: rdf[4], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[4], line: l} + return } rr.Expiration = j if j, err = dateToTime(rdf[5]); err != nil { - return z, &ParseError{Error: "bad RRSIG", name: rdf[5], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[5], line: l} + return } rr.Inception = j if i, err = strconv.Atoui(rdf[6]); err != nil { - return z, &ParseError{Error: "bad RRSIG", name: rdf[3], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[3], line: l} + return } rr.KeyTag = uint16(i) rr.SignerName = rdf[7] if ! IsDomainName(rdf[7]) { - return z, &ParseError{Error: "bad RRSIG", name: rdf[7], line: l} + zp.Err <- &ParseError{Error: "bad RRSIG", name: rdf[7], line: l} + return } // Check base64 TODO rr.Signature = rdf[8] - z.PushRR(rr) + zp.RR <- rr } action setNSEC { @@ -259,7 +289,7 @@ // Check if its there in the map TODO rr.TypeBitMap[i-1] = str_rr[strings.ToUpper(rdf[i])] } - z.PushRR(rr) + zp.RR <- rr } action setNSEC3 { @@ -273,15 +303,18 @@ rr.Hdr.Rrtype = TypeNSEC3 if i, e = strconv.Atoui(rdf[0]); e != nil { - return z, &ParseError{Error: "bad NSEC3", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad NSEC3", name: rdf[0], line: l} + return } rr.Hash = uint8(i) if i, e = strconv.Atoui(rdf[1]); e != nil { - return z, &ParseError{Error: "bad NSEC3", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad NSEC3", name: rdf[1], line: l} + return } rr.Flags = uint8(i) if i, e = strconv.Atoui(rdf[2]); e != nil { - return z, &ParseError{Error: "bad NSEC3", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad NSEC3", name: rdf[2], line: l} + return } rr.Iterations = uint16(i) rr.SaltLength = uint8(len(rdf[3])) @@ -295,7 +328,7 @@ // Check if its there in the map TODO rr.TypeBitMap[i-5] = str_rr[strings.ToUpper(rdf[i])] } - z.PushRR(rr) + zp.RR <- rr } action setNSEC3PARAM { @@ -308,23 +341,23 @@ rr.Hdr = hdr rr.Hdr.Rrtype = TypeNSEC3PARAM if i, e = strconv.Atoi(rdf[0]); e != nil { - return z, &ParseError{Error: "bad NSEC3PARAM", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad NSEC3PARAM", name: rdf[0], line: l} + return } rr.Hash = uint8(i) if i, e = strconv.Atoi(rdf[1]); e != nil { - return z, &ParseError{Error: "bad NSEC3PARAM", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad NSEC3PARAM", name: rdf[1], line: l} + return } rr.Flags = uint8(i) if i, e = strconv.Atoi(rdf[2]); e != nil { - return z, &ParseError{Error: "bad NSEC3PARAM", name: rdf[2], line: l} + zp.Err <- &ParseError{Error: "bad NSEC3PARAM", name: rdf[2], line: l} + return } rr.Iterations = uint16(i) rr.Salt = rdf[3] rr.SaltLength = uint8(len(rr.Salt)) - z.PushRR(rr) - } - - action setPRT { + zp.RR <- rr } action setTXT { @@ -333,7 +366,7 @@ rr.Hdr = hdr rr.Hdr.Rrtype = TypeTXT rr.Txt = rdf[0] - z.PushRR(rr) + zp.RR <- rr } action setSRV { @@ -361,14 +394,16 @@ rr.Hdr = hdr rr.Hdr.Rrtype = TypeSSHFP if i, e = strconv.Atoi(rdf[0]); e != nil { - return z, &ParseError{Error: "bad SSHFP", name: rdf[0], line: l} + zp.Err <- &ParseError{Error: "bad SSHFP", name: rdf[0], line: l} + return } rr.Algorithm = uint8(i) if i, e = strconv.Atoi(rdf[1]); e != nil { - return z, &ParseError{Error: "bad SSHFP", name: rdf[1], line: l} + zp.Err <- &ParseError{Error: "bad SSHFP", name: rdf[1], line: l} + return } rr.Type = uint8(i) rr.FingerPrint = rdf[2] - z.PushRR(rr) + zp.RR <- rr } }%% diff --git a/zparse.go b/zparse.go index 514e5554..23230352 100644 --- a/zparse.go +++ b/zparse.go @@ -33,6 +33,12 @@ func (e *ParseError) String() string { return s } +// First will return the first RR found when parsing. +func (zp *Parser) First() (RR, os.Error) { + // defer close something + return nil, nil +} + // NewParser creates a new DNS file parser from r. func NewParser(r io.Reader) *Parser { buf := make([]byte, _IOBUF) @@ -91,18 +97,8 @@ var z_en_main int = 141 // line 85 "zparse.rl" - -// RR parses a zone file, but only returns the last RR read. -func (zp *Parser) RR() (RR, os.Error) { - z, err := zp.Zone() - if err != nil { - return nil, err - } - return z.PopRR(), nil -} - // Zone parses an DNS master zone file. -func (zp *Parser) Zone() (z *Zone, err os.Error) { +func (zp *Parser) Zone() (err os.Error) { /* z = NewZone() data := string(zp.buf) @@ -3801,13 +3797,13 @@ func (zp *Parser) Zone() (z *Zone, err os.Error) { println("p", p, "pe", pe) println("cs", cs, "z_first_final", z_first_final) println("unexpected eof at line ", l) - return z, nil + return nil } else { println("error at position ", p, "\"", data[mark:p], "\" at line ", l) - return z, nil + return nil } } } */ - return z, nil + return nil } diff --git a/zparse.rl b/zparse.rl index 85e0b79f..0fe81cd1 100644 --- a/zparse.rl +++ b/zparse.rl @@ -21,6 +21,7 @@ type Parser struct { // nothing here yet buf []byte RR chan RR + Error chan *ParseError } type ParseError struct { @@ -35,6 +36,7 @@ func (e *ParseError) String() string { } // NewParser creates a new DNS file parser from r. +// Need sliding window stuff TODO. func NewParser(r io.Reader) *Parser { buf := make([]byte, _IOBUF) n, err := r.Read(buf) @@ -48,7 +50,8 @@ func NewParser(r io.Reader) *Parser { buf = buf[:n] p := new(Parser) p.buf = buf - p.RR = make(chan RR) + p.RR = make(chan RR) + p.Error = make(chan ParseError) return p } @@ -87,37 +90,52 @@ func fields(s string, i int) (rdf []string) { write data; }%% -// RR parses a zone file, but only returns the last RR read. -func (zp *Parser) RR() (RR, os.Error) { - z, err := zp.Zone() - if err != nil { - return nil, err +// First will return the first RR found when parsing. +func (zp *Parser) First() (RR, os.Error) { + // defer close something + go run(zp, quit) + select { + case r := <-zp.RR: + return r, nil + case e := <-zp.Error: + return nil, e } - return z.PopRR(), nil +} + + +// Run starts the parsers and returns the parsed Rr on the RR channel. +// Errors are return on the Error channel. After an error the parsing stops. +func (zp *Parser) Run(quit chan bool) { + go run(zp, quit) } // Run parses an DNS master zone file. It returns each parsed RR // on the channel as soon as it has been parsed. -func (zp *Parser) Run() (err os.Error) { +func run(zp *Parser, quit chan bool) (err os.Error) { data := string(zp.buf) cs, p, pe := 0, 0, len(data) eof := len(data) + defer close(zp.Error) + defer close(zp.RR) + // brace := false l := 1 // or... 0? mark := 0 var hdr RR_Header + // Need to listen to the quit channel %%{ action mark { mark = p } action lineCount { l++ } action setQname { if ! IsDomainName(data[mark:p]) { - return z, &ParseError{Error: "bad qname: " + data[mark:p], line: l} + zp.Error <- &ParseError{Error: "bad qname: " + data[mark:p], line: l} + return } hdr.Name = data[mark:p] } - action errQclass { return z, &ParseError{Error: "bad qclass: " + data[mark:p], line: l} } + action errQclass { zp.Error <- &ParseError{Error: "bad qclass: " + data[mark:p], line: l}; return } action setQclass { hdr.Class = str_class[data[mark:p]] } action defTtl { /* ... */ } action errTtl { /* ... */ } @@ -186,12 +204,12 @@ func (zp *Parser) Run() (err os.Error) { println("p", p, "pe", pe) println("cs", cs, "z_first_final", z_first_final) println("unexpected eof at line ", l) - return z, nil + return } else { println("error at position ", p, "\"",data[mark:p],"\" at line ", l) - return z, nil + return } } } - return z, nil + return }