dns/zparse.rl

167 lines
4.8 KiB
Plaintext
Raw Normal View History

2011-07-21 12:32:02 +00:00
package dns
// Parse RRs
// With the thankful help of gdnsd and the Go examples for Ragel.
//
import (
"os"
"io"
"net"
"strings"
2011-07-21 12:32:02 +00:00
"strconv"
)
2011-07-22 10:49:03 +00:00
//const _IOBUF = 65365
const _IOBUF = 3e7
2011-07-21 12:32:02 +00:00
// Return the rdata fields as a slice. All starting whitespace deleted
func fields(s string, i int) (rdf []string) {
rdf = strings.Fields(strings.TrimSpace(s))
for i, _ := range rdf {
rdf[i] = strings.TrimSpace(rdf[i])
}
// every rdf above i should be stiched together without
// the spaces
return
2011-07-21 12:32:02 +00:00
}
2011-07-22 10:49:03 +00:00
func atoi(s string) uint {
i, err := strconv.Atoui(s)
if err != nil {
2011-07-22 10:49:03 +00:00
panic("not a number: " + s + " " + err.String())
}
return i
2011-07-21 12:32:02 +00:00
}
/*
2011-07-21 12:32:02 +00:00
func rdata_ds(hdr RR_Header, tok *token) RR {
rr := new(RR_DS)
rr.Hdr = hdr;
rr.Hdr.Rrtype = TypeDS
rr.KeyTag = uint16(tok.N[0])
rr.Algorithm = uint8(tok.N[1])
rr.DigestType = uint8(tok.N[2])
rr.Digest = tok.T[0]
return rr
}
func rdata_dnskey(hdr RR_Header, tok *token) RR {
rr := new(RR_DNSKEY)
rr.Hdr = hdr;
rr.Hdr.Rrtype = TypeDNSKEY
rr.Flags = uint16(tok.N[0])
rr.Protocol = uint8(tok.N[1])
rr.Algorithm = uint8(tok.N[2])
rr.PublicKey = tok.T[0]
return rr
}
func rdata_rrsig(hdr RR_Header, tok *token) RR {
rr := new(RR_RRSIG)
rr.Hdr = hdr;
rr.Hdr.Rrtype = TypeRRSIG
rr.TypeCovered = uint16(tok.N[0])
rr.Algorithm = uint8(tok.N[1])
rr.Labels = uint8(tok.N[2])
rr.OrigTtl = uint32(tok.N[3])
rr.Expiration = uint32(tok.N[4])
rr.Inception = uint32(tok.N[5])
rr.KeyTag = uint16(tok.N[6])
rr.SignerName = tok.T[0]
rr.Signature = tok.T[1]
return rr
}
*/
2011-07-21 12:32:02 +00:00
%%{
machine z;
write data;
}%%
// SetString
// All the NewReader stuff is expensive...
// only works for short io.Readers as we put the whole thing
// in a string -- needs to be extended for large files (sliding window).
func Zparse(q io.Reader) (z *Zone, err os.Error) {
buf := make([]byte, _IOBUF)
n, err := q.Read(buf)
if err != nil {
return nil, err
}
buf = buf[:n]
z = new(Zone)
data := string(buf)
cs, p, pe := 0, 0, len(data)
eof := len(data)
// brace := false
2011-07-21 12:32:02 +00:00
lines := 0
mark := 0
hdr := new(RR_Header)
%%{
action mark { mark = p }
action setQname { hdr.Name = data[mark:p] }
action setQclass { hdr.Class = Str_class[data[mark:p]] }
2011-07-21 12:32:02 +00:00
action defTtl { /* ... */ }
2011-07-22 10:49:03 +00:00
action setTtl { ttl := atoi(data[mark:p]); hdr.Ttl = uint32(ttl) }
action lineCount { lines++ }
2011-07-21 12:32:02 +00:00
# action openBrace { if brace { println("Brace already open")} ; brace = true }
# action closeBrace { if !brace { println("Brace already closed")}; brace = false }
# action brace { brace }
2011-07-21 12:32:02 +00:00
include "types.rl";
2011-07-21 12:32:02 +00:00
nl = [\n]+ $lineCount;
comment = ';' [^\n]*;
2011-07-22 10:49:03 +00:00
ttl = digit+ >mark;
# bl = ( [ \t]+
# | '(' $openBrace
# | ')' $closeBrace
# | (comment? nl)+ when brace
# )+ %mark;
bl = [ \t]+;
# rdata = [a-zA-Z0-9.]+ >mark;
rdata = [^\n]+ >mark;
qname = [a-zA-Z0-9.\-_]+ >mark %setQname;
qclass = ('IN'i|'CH'i|'HS'i) >mark %setQclass;
2011-07-21 12:32:02 +00:00
lhs = qname? bl %defTtl (
(ttl %setTtl bl (qclass bl)?)
| (qclass bl (ttl %setTtl bl)?)
)?;
rhs = (
( 'A'i rdata ) %setA
| ( 'AAAA'i rdata ) %setAAAA
| ( 'SOA'i rdata ) %setSOA
| ( 'CNAME'i rdata ) %setCNAME
| ( 'NS'i rdata ) %setNS
| ( 'MX'i rdata ) %setMX
);
rr = lhs rhs;
# main := (rr? bl? ((comment? nl) when !brace))*;
main := (rr? nl)*;
2011-07-21 12:32:02 +00:00
write init;
write exec;
}%%
if eof > -1 {
if cs < z_first_final {
// No clue what I'm doing what so ever
if p == pe {
2011-07-22 10:49:03 +00:00
println("unexpected eof at line", lines)
2011-07-21 12:32:02 +00:00
return z, nil
} else {
2011-07-22 10:49:03 +00:00
println("error at position ", p, "\"",data[mark:p],"\" at line ", lines)
2011-07-21 12:32:02 +00:00
return z, nil
}
}
}
return z, nil
}