scan.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. package dns
  2. import (
  3. "io"
  4. "log"
  5. "os"
  6. "strconv"
  7. "strings"
  8. )
  9. type debugging bool
  10. const debug debugging = false
  11. func (d debugging) Printf(format string, args ...interface{}) {
  12. if d {
  13. log.Printf(format, args...)
  14. }
  15. }
  16. const maxTok = 2048 // Largest token we can return.
  17. const maxUint16 = 1<<16 - 1
  18. // Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
  19. // * Add ownernames if they are left blank;
  20. // * Suppress sequences of spaces;
  21. // * Make each RR fit on one line (_NEWLINE is send as last)
  22. // * Handle comments: ;
  23. // * Handle braces - anywhere.
  24. const (
  25. // Zonefile
  26. zEOF = iota
  27. zString
  28. zBlank
  29. zQuote
  30. zNewline
  31. zRrtpe
  32. zOwner
  33. zClass
  34. zDirOrigin // $ORIGIN
  35. zDirTtl // $TTL
  36. zDirInclude // $INCLUDE
  37. zDirGenerate // $GENERATE
  38. // Privatekey file
  39. zValue
  40. zKey
  41. zExpectOwnerDir // Ownername
  42. zExpectOwnerBl // Whitespace after the ownername
  43. zExpectAny // Expect rrtype, ttl or class
  44. zExpectAnyNoClass // Expect rrtype or ttl
  45. zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
  46. zExpectAnyNoTtl // Expect rrtype or class
  47. zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
  48. zExpectRrtype // Expect rrtype
  49. zExpectRrtypeBl // Whitespace BEFORE rrtype
  50. zExpectRdata // The first element of the rdata
  51. zExpectDirTtlBl // Space after directive $TTL
  52. zExpectDirTtl // Directive $TTL
  53. zExpectDirOriginBl // Space after directive $ORIGIN
  54. zExpectDirOrigin // Directive $ORIGIN
  55. zExpectDirIncludeBl // Space after directive $INCLUDE
  56. zExpectDirInclude // Directive $INCLUDE
  57. zExpectDirGenerate // Directive $GENERATE
  58. zExpectDirGenerateBl // Space after directive $GENERATE
  59. )
  60. // ParseError is a parsing error. It contains the parse error and the location in the io.Reader
  61. // where the error occurred.
  62. type ParseError struct {
  63. file string
  64. err string
  65. lex lex
  66. }
  67. func (e *ParseError) Error() (s string) {
  68. if e.file != "" {
  69. s = e.file + ": "
  70. }
  71. s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
  72. strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
  73. return
  74. }
  75. type lex struct {
  76. token string // text of the token
  77. tokenUpper string // uppercase text of the token
  78. length int // length of the token
  79. err bool // when true, token text has lexer error
  80. value uint8 // value: zString, _BLANK, etc.
  81. line int // line in the file
  82. column int // column in the file
  83. torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
  84. comment string // any comment text seen
  85. }
  86. // Token holds the token that are returned when a zone file is parsed.
  87. type Token struct {
  88. // The scanned resource record when error is not nil.
  89. RR
  90. // When an error occurred, this has the error specifics.
  91. Error *ParseError
  92. // A potential comment positioned after the RR and on the same line.
  93. Comment string
  94. }
  95. // NewRR reads the RR contained in the string s. Only the first RR is
  96. // returned. If s contains no RR, return nil with no error. The class
  97. // defaults to IN and TTL defaults to 3600. The full zone file syntax
  98. // like $TTL, $ORIGIN, etc. is supported. All fields of the returned
  99. // RR are set, except RR.Header().Rdlength which is set to 0.
  100. func NewRR(s string) (RR, error) {
  101. if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
  102. return ReadRR(strings.NewReader(s+"\n"), "")
  103. }
  104. return ReadRR(strings.NewReader(s), "")
  105. }
  106. // ReadRR reads the RR contained in q.
  107. // See NewRR for more documentation.
  108. func ReadRR(q io.Reader, filename string) (RR, error) {
  109. r := <-parseZoneHelper(q, ".", filename, 1)
  110. if r == nil {
  111. return nil, nil
  112. }
  113. if r.Error != nil {
  114. return nil, r.Error
  115. }
  116. return r.RR, nil
  117. }
  118. // ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
  119. // returned channel, which consist out the parsed RR, a potential comment or an error.
  120. // If there is an error the RR is nil. The string file is only used
  121. // in error reporting. The string origin is used as the initial origin, as
  122. // if the file would start with: $ORIGIN origin .
  123. // The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
  124. // The channel t is closed by ParseZone when the end of r is reached.
  125. //
  126. // Basic usage pattern when reading from a string (z) containing the
  127. // zone data:
  128. //
  129. // for x := range dns.ParseZone(strings.NewReader(z), "", "") {
  130. // if x.Error != nil {
  131. // // log.Println(x.Error)
  132. // } else {
  133. // // Do something with x.RR
  134. // }
  135. // }
  136. //
  137. // Comments specified after an RR (and on the same line!) are returned too:
  138. //
  139. // foo. IN A 10.0.0.1 ; this is a comment
  140. //
  141. // The text "; this is comment" is returned in Token.Comment. Comments inside the
  142. // RR are discarded. Comments on a line by themselves are discarded too.
  143. func ParseZone(r io.Reader, origin, file string) chan *Token {
  144. return parseZoneHelper(r, origin, file, 10000)
  145. }
  146. func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
  147. t := make(chan *Token, chansize)
  148. go parseZone(r, origin, file, t, 0)
  149. return t
  150. }
  151. func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
  152. defer func() {
  153. if include == 0 {
  154. close(t)
  155. }
  156. }()
  157. s := scanInit(r)
  158. c := make(chan lex)
  159. // Start the lexer
  160. go zlexer(s, c)
  161. // 6 possible beginnings of a line, _ is a space
  162. // 0. zRRTYPE -> all omitted until the rrtype
  163. // 1. zOwner _ zRrtype -> class/ttl omitted
  164. // 2. zOwner _ zString _ zRrtype -> class omitted
  165. // 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
  166. // 4. zOwner _ zClass _ zRrtype -> ttl omitted
  167. // 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
  168. // After detecting these, we know the zRrtype so we can jump to functions
  169. // handling the rdata for each of these types.
  170. if origin == "" {
  171. origin = "."
  172. }
  173. origin = Fqdn(origin)
  174. if _, ok := IsDomainName(origin); !ok {
  175. t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
  176. return
  177. }
  178. st := zExpectOwnerDir // initial state
  179. var h RR_Header
  180. var defttl uint32 = defaultTtl
  181. var prevName string
  182. for l := range c {
  183. // Lexer spotted an error already
  184. if l.err == true {
  185. t <- &Token{Error: &ParseError{f, l.token, l}}
  186. return
  187. }
  188. switch st {
  189. case zExpectOwnerDir:
  190. // We can also expect a directive, like $TTL or $ORIGIN
  191. h.Ttl = defttl
  192. h.Class = ClassINET
  193. switch l.value {
  194. case zNewline:
  195. st = zExpectOwnerDir
  196. case zOwner:
  197. h.Name = l.token
  198. if l.token[0] == '@' {
  199. h.Name = origin
  200. prevName = h.Name
  201. st = zExpectOwnerBl
  202. break
  203. }
  204. if h.Name[l.length-1] != '.' {
  205. h.Name = appendOrigin(h.Name, origin)
  206. }
  207. _, ok := IsDomainName(l.token)
  208. if !ok {
  209. t <- &Token{Error: &ParseError{f, "bad owner name", l}}
  210. return
  211. }
  212. prevName = h.Name
  213. st = zExpectOwnerBl
  214. case zDirTtl:
  215. st = zExpectDirTtlBl
  216. case zDirOrigin:
  217. st = zExpectDirOriginBl
  218. case zDirInclude:
  219. st = zExpectDirIncludeBl
  220. case zDirGenerate:
  221. st = zExpectDirGenerateBl
  222. case zRrtpe:
  223. h.Name = prevName
  224. h.Rrtype = l.torc
  225. st = zExpectRdata
  226. case zClass:
  227. h.Name = prevName
  228. h.Class = l.torc
  229. st = zExpectAnyNoClassBl
  230. case zBlank:
  231. // Discard, can happen when there is nothing on the
  232. // line except the RR type
  233. case zString:
  234. ttl, ok := stringToTtl(l.token)
  235. if !ok {
  236. t <- &Token{Error: &ParseError{f, "not a TTL", l}}
  237. return
  238. }
  239. h.Ttl = ttl
  240. // Don't about the defttl, we should take the $TTL value
  241. // defttl = ttl
  242. st = zExpectAnyNoTtlBl
  243. default:
  244. t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
  245. return
  246. }
  247. case zExpectDirIncludeBl:
  248. if l.value != zBlank {
  249. t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
  250. return
  251. }
  252. st = zExpectDirInclude
  253. case zExpectDirInclude:
  254. if l.value != zString {
  255. t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
  256. return
  257. }
  258. neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
  259. l := <-c
  260. switch l.value {
  261. case zBlank:
  262. l := <-c
  263. if l.value == zString {
  264. if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
  265. t <- &Token{Error: &ParseError{f, "bad origin name", l}}
  266. return
  267. }
  268. // a new origin is specified.
  269. if l.token[l.length-1] != '.' {
  270. if origin != "." { // Prevent .. endings
  271. neworigin = l.token + "." + origin
  272. } else {
  273. neworigin = l.token + origin
  274. }
  275. } else {
  276. neworigin = l.token
  277. }
  278. }
  279. case zNewline, zEOF:
  280. // Ok
  281. default:
  282. t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
  283. return
  284. }
  285. // Start with the new file
  286. r1, e1 := os.Open(l.token)
  287. if e1 != nil {
  288. t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
  289. return
  290. }
  291. if include+1 > 7 {
  292. t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
  293. return
  294. }
  295. parseZone(r1, l.token, neworigin, t, include+1)
  296. st = zExpectOwnerDir
  297. case zExpectDirTtlBl:
  298. if l.value != zBlank {
  299. t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
  300. return
  301. }
  302. st = zExpectDirTtl
  303. case zExpectDirTtl:
  304. if l.value != zString {
  305. t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
  306. return
  307. }
  308. if e, _ := slurpRemainder(c, f); e != nil {
  309. t <- &Token{Error: e}
  310. return
  311. }
  312. ttl, ok := stringToTtl(l.token)
  313. if !ok {
  314. t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
  315. return
  316. }
  317. defttl = ttl
  318. st = zExpectOwnerDir
  319. case zExpectDirOriginBl:
  320. if l.value != zBlank {
  321. t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
  322. return
  323. }
  324. st = zExpectDirOrigin
  325. case zExpectDirOrigin:
  326. if l.value != zString {
  327. t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
  328. return
  329. }
  330. if e, _ := slurpRemainder(c, f); e != nil {
  331. t <- &Token{Error: e}
  332. }
  333. if _, ok := IsDomainName(l.token); !ok {
  334. t <- &Token{Error: &ParseError{f, "bad origin name", l}}
  335. return
  336. }
  337. if l.token[l.length-1] != '.' {
  338. if origin != "." { // Prevent .. endings
  339. origin = l.token + "." + origin
  340. } else {
  341. origin = l.token + origin
  342. }
  343. } else {
  344. origin = l.token
  345. }
  346. st = zExpectOwnerDir
  347. case zExpectDirGenerateBl:
  348. if l.value != zBlank {
  349. t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
  350. return
  351. }
  352. st = zExpectDirGenerate
  353. case zExpectDirGenerate:
  354. if l.value != zString {
  355. t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
  356. return
  357. }
  358. if errMsg := generate(l, c, t, origin); errMsg != "" {
  359. t <- &Token{Error: &ParseError{f, errMsg, l}}
  360. return
  361. }
  362. st = zExpectOwnerDir
  363. case zExpectOwnerBl:
  364. if l.value != zBlank {
  365. t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
  366. return
  367. }
  368. st = zExpectAny
  369. case zExpectAny:
  370. switch l.value {
  371. case zRrtpe:
  372. h.Rrtype = l.torc
  373. st = zExpectRdata
  374. case zClass:
  375. h.Class = l.torc
  376. st = zExpectAnyNoClassBl
  377. case zString:
  378. ttl, ok := stringToTtl(l.token)
  379. if !ok {
  380. t <- &Token{Error: &ParseError{f, "not a TTL", l}}
  381. return
  382. }
  383. h.Ttl = ttl
  384. // defttl = ttl // don't set the defttl here
  385. st = zExpectAnyNoTtlBl
  386. default:
  387. t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
  388. return
  389. }
  390. case zExpectAnyNoClassBl:
  391. if l.value != zBlank {
  392. t <- &Token{Error: &ParseError{f, "no blank before class", l}}
  393. return
  394. }
  395. st = zExpectAnyNoClass
  396. case zExpectAnyNoTtlBl:
  397. if l.value != zBlank {
  398. t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
  399. return
  400. }
  401. st = zExpectAnyNoTtl
  402. case zExpectAnyNoTtl:
  403. switch l.value {
  404. case zClass:
  405. h.Class = l.torc
  406. st = zExpectRrtypeBl
  407. case zRrtpe:
  408. h.Rrtype = l.torc
  409. st = zExpectRdata
  410. default:
  411. t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
  412. return
  413. }
  414. case zExpectAnyNoClass:
  415. switch l.value {
  416. case zString:
  417. ttl, ok := stringToTtl(l.token)
  418. if !ok {
  419. t <- &Token{Error: &ParseError{f, "not a TTL", l}}
  420. return
  421. }
  422. h.Ttl = ttl
  423. // defttl = ttl // don't set the def ttl anymore
  424. st = zExpectRrtypeBl
  425. case zRrtpe:
  426. h.Rrtype = l.torc
  427. st = zExpectRdata
  428. default:
  429. t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
  430. return
  431. }
  432. case zExpectRrtypeBl:
  433. if l.value != zBlank {
  434. t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
  435. return
  436. }
  437. st = zExpectRrtype
  438. case zExpectRrtype:
  439. if l.value != zRrtpe {
  440. t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
  441. return
  442. }
  443. h.Rrtype = l.torc
  444. st = zExpectRdata
  445. case zExpectRdata:
  446. r, e, c1 := setRR(h, c, origin, f)
  447. if e != nil {
  448. // If e.lex is nil than we have encounter a unknown RR type
  449. // in that case we substitute our current lex token
  450. if e.lex.token == "" && e.lex.value == 0 {
  451. e.lex = l // Uh, dirty
  452. }
  453. t <- &Token{Error: e}
  454. return
  455. }
  456. t <- &Token{RR: r, Comment: c1}
  457. st = zExpectOwnerDir
  458. }
  459. }
  460. // If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
  461. // is not an error, because an empty zone file is still a zone file.
  462. }
  463. // zlexer scans the sourcefile and returns tokens on the channel c.
  464. func zlexer(s *scan, c chan lex) {
  465. var l lex
  466. str := make([]byte, maxTok) // Should be enough for any token
  467. stri := 0 // Offset in str (0 means empty)
  468. com := make([]byte, maxTok) // Hold comment text
  469. comi := 0
  470. quote := false
  471. escape := false
  472. space := false
  473. commt := false
  474. rrtype := false
  475. owner := true
  476. brace := 0
  477. x, err := s.tokenText()
  478. defer close(c)
  479. for err == nil {
  480. l.column = s.position.Column
  481. l.line = s.position.Line
  482. if stri >= maxTok {
  483. l.token = "token length insufficient for parsing"
  484. l.err = true
  485. debug.Printf("[%+v]", l.token)
  486. c <- l
  487. return
  488. }
  489. if comi >= maxTok {
  490. l.token = "comment length insufficient for parsing"
  491. l.err = true
  492. debug.Printf("[%+v]", l.token)
  493. c <- l
  494. return
  495. }
  496. switch x {
  497. case ' ', '\t':
  498. if escape {
  499. escape = false
  500. str[stri] = x
  501. stri++
  502. break
  503. }
  504. if quote {
  505. // Inside quotes this is legal
  506. str[stri] = x
  507. stri++
  508. break
  509. }
  510. if commt {
  511. com[comi] = x
  512. comi++
  513. break
  514. }
  515. if stri == 0 {
  516. // Space directly in the beginning, handled in the grammar
  517. } else if owner {
  518. // If we have a string and its the first, make it an owner
  519. l.value = zOwner
  520. l.token = string(str[:stri])
  521. l.tokenUpper = strings.ToUpper(l.token)
  522. l.length = stri
  523. // escape $... start with a \ not a $, so this will work
  524. switch l.tokenUpper {
  525. case "$TTL":
  526. l.value = zDirTtl
  527. case "$ORIGIN":
  528. l.value = zDirOrigin
  529. case "$INCLUDE":
  530. l.value = zDirInclude
  531. case "$GENERATE":
  532. l.value = zDirGenerate
  533. }
  534. debug.Printf("[7 %+v]", l.token)
  535. c <- l
  536. } else {
  537. l.value = zString
  538. l.token = string(str[:stri])
  539. l.tokenUpper = strings.ToUpper(l.token)
  540. l.length = stri
  541. if !rrtype {
  542. if t, ok := StringToType[l.tokenUpper]; ok {
  543. l.value = zRrtpe
  544. l.torc = t
  545. rrtype = true
  546. } else {
  547. if strings.HasPrefix(l.tokenUpper, "TYPE") {
  548. t, ok := typeToInt(l.token)
  549. if !ok {
  550. l.token = "unknown RR type"
  551. l.err = true
  552. c <- l
  553. return
  554. }
  555. l.value = zRrtpe
  556. l.torc = t
  557. }
  558. }
  559. if t, ok := StringToClass[l.tokenUpper]; ok {
  560. l.value = zClass
  561. l.torc = t
  562. } else {
  563. if strings.HasPrefix(l.tokenUpper, "CLASS") {
  564. t, ok := classToInt(l.token)
  565. if !ok {
  566. l.token = "unknown class"
  567. l.err = true
  568. c <- l
  569. return
  570. }
  571. l.value = zClass
  572. l.torc = t
  573. }
  574. }
  575. }
  576. debug.Printf("[6 %+v]", l.token)
  577. c <- l
  578. }
  579. stri = 0
  580. // I reverse space stuff here
  581. if !space && !commt {
  582. l.value = zBlank
  583. l.token = " "
  584. l.length = 1
  585. debug.Printf("[5 %+v]", l.token)
  586. c <- l
  587. }
  588. owner = false
  589. space = true
  590. case ';':
  591. if escape {
  592. escape = false
  593. str[stri] = x
  594. stri++
  595. break
  596. }
  597. if quote {
  598. // Inside quotes this is legal
  599. str[stri] = x
  600. stri++
  601. break
  602. }
  603. if stri > 0 {
  604. l.value = zString
  605. l.token = string(str[:stri])
  606. l.length = stri
  607. debug.Printf("[4 %+v]", l.token)
  608. c <- l
  609. stri = 0
  610. }
  611. commt = true
  612. com[comi] = ';'
  613. comi++
  614. case '\r':
  615. escape = false
  616. if quote {
  617. str[stri] = x
  618. stri++
  619. break
  620. }
  621. // discard if outside of quotes
  622. case '\n':
  623. escape = false
  624. // Escaped newline
  625. if quote {
  626. str[stri] = x
  627. stri++
  628. break
  629. }
  630. // inside quotes this is legal
  631. if commt {
  632. // Reset a comment
  633. commt = false
  634. rrtype = false
  635. stri = 0
  636. // If not in a brace this ends the comment AND the RR
  637. if brace == 0 {
  638. owner = true
  639. owner = true
  640. l.value = zNewline
  641. l.token = "\n"
  642. l.length = 1
  643. l.comment = string(com[:comi])
  644. debug.Printf("[3 %+v %+v]", l.token, l.comment)
  645. c <- l
  646. l.comment = ""
  647. comi = 0
  648. break
  649. }
  650. com[comi] = ' ' // convert newline to space
  651. comi++
  652. break
  653. }
  654. if brace == 0 {
  655. // If there is previous text, we should output it here
  656. if stri != 0 {
  657. l.value = zString
  658. l.token = string(str[:stri])
  659. l.tokenUpper = strings.ToUpper(l.token)
  660. l.length = stri
  661. if !rrtype {
  662. if t, ok := StringToType[l.tokenUpper]; ok {
  663. l.value = zRrtpe
  664. l.torc = t
  665. rrtype = true
  666. }
  667. }
  668. debug.Printf("[2 %+v]", l.token)
  669. c <- l
  670. }
  671. l.value = zNewline
  672. l.token = "\n"
  673. l.length = 1
  674. debug.Printf("[1 %+v]", l.token)
  675. c <- l
  676. stri = 0
  677. commt = false
  678. rrtype = false
  679. owner = true
  680. comi = 0
  681. }
  682. case '\\':
  683. // comments do not get escaped chars, everything is copied
  684. if commt {
  685. com[comi] = x
  686. comi++
  687. break
  688. }
  689. // something already escaped must be in string
  690. if escape {
  691. str[stri] = x
  692. stri++
  693. escape = false
  694. break
  695. }
  696. // something escaped outside of string gets added to string
  697. str[stri] = x
  698. stri++
  699. escape = true
  700. case '"':
  701. if commt {
  702. com[comi] = x
  703. comi++
  704. break
  705. }
  706. if escape {
  707. str[stri] = x
  708. stri++
  709. escape = false
  710. break
  711. }
  712. space = false
  713. // send previous gathered text and the quote
  714. if stri != 0 {
  715. l.value = zString
  716. l.token = string(str[:stri])
  717. l.length = stri
  718. debug.Printf("[%+v]", l.token)
  719. c <- l
  720. stri = 0
  721. }
  722. // send quote itself as separate token
  723. l.value = zQuote
  724. l.token = "\""
  725. l.length = 1
  726. c <- l
  727. quote = !quote
  728. case '(', ')':
  729. if commt {
  730. com[comi] = x
  731. comi++
  732. break
  733. }
  734. if escape {
  735. str[stri] = x
  736. stri++
  737. escape = false
  738. break
  739. }
  740. if quote {
  741. str[stri] = x
  742. stri++
  743. break
  744. }
  745. switch x {
  746. case ')':
  747. brace--
  748. if brace < 0 {
  749. l.token = "extra closing brace"
  750. l.err = true
  751. debug.Printf("[%+v]", l.token)
  752. c <- l
  753. return
  754. }
  755. case '(':
  756. brace++
  757. }
  758. default:
  759. escape = false
  760. if commt {
  761. com[comi] = x
  762. comi++
  763. break
  764. }
  765. str[stri] = x
  766. stri++
  767. space = false
  768. }
  769. x, err = s.tokenText()
  770. }
  771. if stri > 0 {
  772. // Send remainder
  773. l.token = string(str[:stri])
  774. l.length = stri
  775. l.value = zString
  776. debug.Printf("[%+v]", l.token)
  777. c <- l
  778. }
  779. }
  780. // Extract the class number from CLASSxx
  781. func classToInt(token string) (uint16, bool) {
  782. offset := 5
  783. if len(token) < offset+1 {
  784. return 0, false
  785. }
  786. class, ok := strconv.Atoi(token[offset:])
  787. if ok != nil || class > maxUint16 {
  788. return 0, false
  789. }
  790. return uint16(class), true
  791. }
  792. // Extract the rr number from TYPExxx
  793. func typeToInt(token string) (uint16, bool) {
  794. offset := 4
  795. if len(token) < offset+1 {
  796. return 0, false
  797. }
  798. typ, ok := strconv.Atoi(token[offset:])
  799. if ok != nil || typ > maxUint16 {
  800. return 0, false
  801. }
  802. return uint16(typ), true
  803. }
  804. // Parse things like 2w, 2m, etc, Return the time in seconds.
  805. func stringToTtl(token string) (uint32, bool) {
  806. s := uint32(0)
  807. i := uint32(0)
  808. for _, c := range token {
  809. switch c {
  810. case 's', 'S':
  811. s += i
  812. i = 0
  813. case 'm', 'M':
  814. s += i * 60
  815. i = 0
  816. case 'h', 'H':
  817. s += i * 60 * 60
  818. i = 0
  819. case 'd', 'D':
  820. s += i * 60 * 60 * 24
  821. i = 0
  822. case 'w', 'W':
  823. s += i * 60 * 60 * 24 * 7
  824. i = 0
  825. case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
  826. i *= 10
  827. i += uint32(c) - '0'
  828. default:
  829. return 0, false
  830. }
  831. }
  832. return s + i, true
  833. }
  834. // Parse LOC records' <digits>[.<digits>][mM] into a
  835. // mantissa exponent format. Token should contain the entire
  836. // string (i.e. no spaces allowed)
  837. func stringToCm(token string) (e, m uint8, ok bool) {
  838. if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
  839. token = token[0 : len(token)-1]
  840. }
  841. s := strings.SplitN(token, ".", 2)
  842. var meters, cmeters, val int
  843. var err error
  844. switch len(s) {
  845. case 2:
  846. if cmeters, err = strconv.Atoi(s[1]); err != nil {
  847. return
  848. }
  849. fallthrough
  850. case 1:
  851. if meters, err = strconv.Atoi(s[0]); err != nil {
  852. return
  853. }
  854. case 0:
  855. // huh?
  856. return 0, 0, false
  857. }
  858. ok = true
  859. if meters > 0 {
  860. e = 2
  861. val = meters
  862. } else {
  863. e = 0
  864. val = cmeters
  865. }
  866. for val > 10 {
  867. e++
  868. val /= 10
  869. }
  870. if e > 9 {
  871. ok = false
  872. }
  873. m = uint8(val)
  874. return
  875. }
  876. func appendOrigin(name, origin string) string {
  877. if origin == "." {
  878. return name + origin
  879. }
  880. return name + "." + origin
  881. }
  882. // LOC record helper function
  883. func locCheckNorth(token string, latitude uint32) (uint32, bool) {
  884. switch token {
  885. case "n", "N":
  886. return LOC_EQUATOR + latitude, true
  887. case "s", "S":
  888. return LOC_EQUATOR - latitude, true
  889. }
  890. return latitude, false
  891. }
  892. // LOC record helper function
  893. func locCheckEast(token string, longitude uint32) (uint32, bool) {
  894. switch token {
  895. case "e", "E":
  896. return LOC_EQUATOR + longitude, true
  897. case "w", "W":
  898. return LOC_EQUATOR - longitude, true
  899. }
  900. return longitude, false
  901. }
  902. // "Eat" the rest of the "line". Return potential comments
  903. func slurpRemainder(c chan lex, f string) (*ParseError, string) {
  904. l := <-c
  905. com := ""
  906. switch l.value {
  907. case zBlank:
  908. l = <-c
  909. com = l.comment
  910. if l.value != zNewline && l.value != zEOF {
  911. return &ParseError{f, "garbage after rdata", l}, ""
  912. }
  913. case zNewline:
  914. com = l.comment
  915. case zEOF:
  916. default:
  917. return &ParseError{f, "garbage after rdata", l}, ""
  918. }
  919. return nil, com
  920. }
  921. // Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
  922. // Used for NID and L64 record.
  923. func stringToNodeID(l lex) (uint64, *ParseError) {
  924. if len(l.token) < 19 {
  925. return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
  926. }
  927. // There must be three colons at fixes postitions, if not its a parse error
  928. if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
  929. return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
  930. }
  931. s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
  932. u, err := strconv.ParseUint(s, 16, 64)
  933. if err != nil {
  934. return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
  935. }
  936. return u, nil
  937. }