func ParseNS(name string, ttl int32, rdclass string, zstate *ZoneState, s *scanner.Scanner) (rdtype.Rdtyper, error) { cur := <-s.Next() if err := goodToken(&cur); err != nil { return nil, err } targetName := trueName(zstate, cur.Value) if err := requireDNSName(&cur.Value); err != nil { return nil, err } ns := rdtype.NS{name, ttl, targetName} return rdtype.Rdtyper(ns), nil }
func parseSOAInt32(s *scanner.Scanner, cur scanner.Token) (int32, error) { cur = <-s.Next() if err := goodToken(&cur); err != nil { return 0, err } i, err := requireInt32(cur.Value) if err != nil { return 0, err } if err := ClearCommentNewLine(s); err != nil { return 0, err } return i, nil }
func ParseNewLines(s *scanner.Scanner) (bool, error) { // ParseNewLines: Consume newlines ret := false for { peek := <-s.Peek() //if err := goodToken(&peek); err != nil {return false, err} if peek.Value == "\n" { ret = true <-s.Next() continue } break } return ret, nil }
func ParseComment(s *scanner.Scanner) (bool, string, error) { // ParseComment: Consume a comment if it exists. Stop leaving \n next // return: // - bool: if a comment was parsed // - string: the comment that was parsed // - error: errors next := <-s.PeekUntil(`[\n;]`) if next.Value != ";" { return false, "", nil } for { peek := <-s.Peek() if peek.Value == "\n" || peek.End { break } <-s.Next() } return true, "", nil }
func ParseDirective(zstate *ZoneState, s *scanner.Scanner) ([]rdtype.Rdtyper, error) { // Assume s.Peek() is looking at $<something> #someoneelsesjob // $TTL sets zstate.Ttl // $ORIGIN sets zstate.Origin // $GENERATE returns []rdtype.RDtyper var value string directive := (<-s.Next()).Value switch directive { case "$TTL": value = (<-s.Next()).Value if ttl, err := strconv.ParseInt(value, 0, 64); err == nil { zstate.Ttl = int32(ttl) } else { return nil, fmt.Errorf("Unable to parse value '%s' as valid ttl\n", ttl) } if _, _, err := ParseComment(s); err != nil { return nil, err } case "$ORIGIN": value = (<-s.Next()).Value if err := requireDNSName(&value); err != nil { return nil, err } zstate.Origin = trueName(zstate, value) if _, _, err := ParseComment(s); err != nil { return nil, err } case "$GENERATE": //TODO goto ERROR } goto SUCCESS ERROR: return nil, fmt.Errorf("Unknown directive '%s'\n", directive) SUCCESS: return nil, nil }
func ParseRecord(zstate *ZoneState, s *scanner.Scanner, dispatch *rdTypeDispatch) (rdtype.Rdtyper, error) { // Parse Record beginning of record then dispatch the record's specific parse function // Three Cases // name ttl class type -- case 2 // 0 1 2 3 // name class type -- case 1 // 0 1 2 // ttl class type -- case 1 // 0 1 2 // class type -- case 0 // 0 1 // If 0 & 1 are class and type -- case 0 // $ORIGIN and $TTL // If 1 & 2 are class and type -- case 1 // if ttl is int32 // $ORIGIN and ttl // else // name and ttl // If 2 & 3 are class and type -- case 2 // name and ttl peeker := s.Peekn(4) tokens := [...]scanner.Token{ <-peeker, <-peeker, <-peeker, <-peeker, } var ttl int32 var name, rdclass, rdtype_ string var valid_class bool for i := 0; i < 3; i++ { cur := tokens[i] next := tokens[i+1] _, valid_class = RDCLASS[strings.ToUpper(cur.Value)] _, valid_rdtype := dispatch.RDType[strings.ToUpper(next.Value)] rdclass = cur.Value rdtype_ = next.Value if valid_class && valid_rdtype { switch i { case 0: <-s.Next() <-s.Next() name = trueName(zstate, "@") ttl = zstate.Ttl goto DISPATCH case 1: <-s.Next() <-s.Next() <-s.Next() // ttl class type // or // name class type ttl_, is_ttl := strconv.ParseInt(tokens[0].Value, 0, 64) if is_ttl != nil { name = trueName(zstate, tokens[0].Value) ttl = zstate.Ttl } else { name = trueName(zstate, "@") ttl = int32(ttl_) } goto DISPATCH case 2: <-s.Next() <-s.Next() <-s.Next() <-s.Next() name = trueName(zstate, tokens[0].Value) ttl_, err := strconv.ParseInt(tokens[1].Value, 0, 64) if err != nil { return nil, err } ttl = int32(ttl_) goto DISPATCH } } } return nil, fmt.Errorf("Could not parse a record!\n") DISPATCH: //fmt.Printf("rdclass='%s' rdtype='%s'\n", rdclass, rdtype_) return dispatch.RDType[rdtype_](name, ttl, rdclass, zstate, s) }
func ParseSOA(name string, ttl int32, rdclass string, zstate *ZoneState, s *scanner.Scanner) (rdtype.Rdtyper, error) { // Assume scanner is currently on rdtype // We expect to see: // primary contact (serial, refresh, retry, exprire, minimum) // Parse out comments and ignore them //fmt.Printf("ParseSOA rdclass='%s' rdtype='%s'\n", rdclass, "SOA") cur := <-s.Next() if err := goodToken(&cur); err != nil { return nil, err } primary := trueName(zstate, cur.Value) //fmt.Printf("primary=%s\n", primary) cur = <-s.NextUntil(`[\n\(]`) if err := goodToken(&cur); err != nil { return nil, err } contact := trueName(zstate, cur.Value) //fmt.Printf("contact=%s\n", contact) if err := ClearCommentNewLine(s); err != nil { return nil, err } //fmt.Printf("peek='%s'\n", (<-s.Peek()).Value) cur = <-s.NextUntil(`[\(\n]`) //fmt.Printf("lparen='%s'\n", cur.Value) //fmt.Printf("peek='%s'\n", (<-s.Peek()).Value) if err := goodToken(&cur); err != nil { return nil, err } if cur.Value != "(" { return nil, fmt.Errorf( "Expected '(' in SOA definition but instead found '%s'\n", cur.Value) } if err := ClearCommentNewLine(s); err != nil { return nil, err } serial, err := parseSOAInt32(s, cur) if err != nil { return nil, err } //fmt.Printf("serial=%d\n", serial) refresh, err := parseSOAInt32(s, cur) if err != nil { return nil, err } //fmt.Printf("refresh=%d\n", refresh) retry, err := parseSOAInt32(s, cur) if err != nil { return nil, err } //fmt.Printf("retry=%d\n", retry) expire, err := parseSOAInt32(s, cur) if err != nil { return nil, err } //fmt.Printf("expire=%d\n", expire) cur = <-s.NextUntil(`[\)\n]`) if err := goodToken(&cur); err != nil { return nil, err } minimum, err := requireInt32(cur.Value) if err != nil { return nil, err } //fmt.Printf("minimum=%d\n", minimum) //fmt.Printf("-------------\n") if err := ClearCommentNewLine(s); err != nil { return nil, err } cur = <-s.Next() if cur.Value != ")" { return nil, fmt.Errorf( "Expected ')' in SOA definition but instead found '%s'\n", cur.Value) } soa := rdtype.SOA{name, ttl, primary, contact, serial, retry, refresh, expire, minimum} return rdtype.Rdtyper(soa), nil }