You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

generate.go 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package dns
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "strconv"
  7. "strings"
  8. )
  9. // Parse the $GENERATE statement as used in BIND9 zones.
  10. // See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
  11. // We are called after '$GENERATE '. After which we expect:
  12. // * the range (12-24/2)
  13. // * lhs (ownername)
  14. // * [[ttl][class]]
  15. // * type
  16. // * rhs (rdata)
  17. // But we are lazy here, only the range is parsed *all* occurrences
  18. // of $ after that are interpreted.
  19. func (zp *ZoneParser) generate(l lex) (RR, bool) {
  20. token := l.token
  21. step := int64(1)
  22. if i := strings.IndexByte(token, '/'); i >= 0 {
  23. if i+1 == len(token) {
  24. return zp.setParseError("bad step in $GENERATE range", l)
  25. }
  26. s, err := strconv.ParseInt(token[i+1:], 10, 64)
  27. if err != nil || s <= 0 {
  28. return zp.setParseError("bad step in $GENERATE range", l)
  29. }
  30. step = s
  31. token = token[:i]
  32. }
  33. sx := strings.SplitN(token, "-", 2)
  34. if len(sx) != 2 {
  35. return zp.setParseError("bad start-stop in $GENERATE range", l)
  36. }
  37. start, err := strconv.ParseInt(sx[0], 10, 64)
  38. if err != nil {
  39. return zp.setParseError("bad start in $GENERATE range", l)
  40. }
  41. end, err := strconv.ParseInt(sx[1], 10, 64)
  42. if err != nil {
  43. return zp.setParseError("bad stop in $GENERATE range", l)
  44. }
  45. if end < 0 || start < 0 || end < start || (end-start)/step > 65535 {
  46. return zp.setParseError("bad range in $GENERATE range", l)
  47. }
  48. // _BLANK
  49. l, ok := zp.c.Next()
  50. if !ok || l.value != zBlank {
  51. return zp.setParseError("garbage after $GENERATE range", l)
  52. }
  53. // Create a complete new string, which we then parse again.
  54. var s string
  55. for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
  56. if l.err {
  57. return zp.setParseError("bad data in $GENERATE directive", l)
  58. }
  59. if l.value == zNewline {
  60. break
  61. }
  62. s += l.token
  63. }
  64. r := &generateReader{
  65. s: s,
  66. cur: start,
  67. start: start,
  68. end: end,
  69. step: step,
  70. file: zp.file,
  71. lex: &l,
  72. }
  73. zp.sub = NewZoneParser(r, zp.origin, zp.file)
  74. zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
  75. zp.sub.generateDisallowed = true
  76. zp.sub.SetDefaultTTL(defaultTtl)
  77. return zp.subNext()
  78. }
  79. type generateReader struct {
  80. s string
  81. si int
  82. cur int64
  83. start int64
  84. end int64
  85. step int64
  86. mod bytes.Buffer
  87. escape bool
  88. eof bool
  89. file string
  90. lex *lex
  91. }
  92. func (r *generateReader) parseError(msg string, end int) *ParseError {
  93. r.eof = true // Make errors sticky.
  94. l := *r.lex
  95. l.token = r.s[r.si-1 : end]
  96. l.column += r.si // l.column starts one zBLANK before r.s
  97. return &ParseError{r.file, msg, l}
  98. }
  99. func (r *generateReader) Read(p []byte) (int, error) {
  100. // NewZLexer, through NewZoneParser, should use ReadByte and
  101. // not end up here.
  102. panic("not implemented")
  103. }
  104. func (r *generateReader) ReadByte() (byte, error) {
  105. if r.eof {
  106. return 0, io.EOF
  107. }
  108. if r.mod.Len() > 0 {
  109. return r.mod.ReadByte()
  110. }
  111. if r.si >= len(r.s) {
  112. r.si = 0
  113. r.cur += r.step
  114. r.eof = r.cur > r.end || r.cur < 0
  115. return '\n', nil
  116. }
  117. si := r.si
  118. r.si++
  119. switch r.s[si] {
  120. case '\\':
  121. if r.escape {
  122. r.escape = false
  123. return '\\', nil
  124. }
  125. r.escape = true
  126. return r.ReadByte()
  127. case '$':
  128. if r.escape {
  129. r.escape = false
  130. return '$', nil
  131. }
  132. mod := "%d"
  133. if si >= len(r.s)-1 {
  134. // End of the string
  135. fmt.Fprintf(&r.mod, mod, r.cur)
  136. return r.mod.ReadByte()
  137. }
  138. if r.s[si+1] == '$' {
  139. r.si++
  140. return '$', nil
  141. }
  142. var offset int64
  143. // Search for { and }
  144. if r.s[si+1] == '{' {
  145. // Modifier block
  146. sep := strings.Index(r.s[si+2:], "}")
  147. if sep < 0 {
  148. return 0, r.parseError("bad modifier in $GENERATE", len(r.s))
  149. }
  150. var errMsg string
  151. mod, offset, errMsg = modToPrintf(r.s[si+2 : si+2+sep])
  152. if errMsg != "" {
  153. return 0, r.parseError(errMsg, si+3+sep)
  154. }
  155. if r.start+offset < 0 || r.end+offset > 1<<31-1 {
  156. return 0, r.parseError("bad offset in $GENERATE", si+3+sep)
  157. }
  158. r.si += 2 + sep // Jump to it
  159. }
  160. fmt.Fprintf(&r.mod, mod, r.cur+offset)
  161. return r.mod.ReadByte()
  162. default:
  163. if r.escape { // Pretty useless here
  164. r.escape = false
  165. return r.ReadByte()
  166. }
  167. return r.s[si], nil
  168. }
  169. }
  170. // Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
  171. func modToPrintf(s string) (string, int64, string) {
  172. // Modifier is { offset [ ,width [ ,base ] ] } - provide default
  173. // values for optional width and type, if necessary.
  174. var offStr, widthStr, base string
  175. switch xs := strings.Split(s, ","); len(xs) {
  176. case 1:
  177. offStr, widthStr, base = xs[0], "0", "d"
  178. case 2:
  179. offStr, widthStr, base = xs[0], xs[1], "d"
  180. case 3:
  181. offStr, widthStr, base = xs[0], xs[1], xs[2]
  182. default:
  183. return "", 0, "bad modifier in $GENERATE"
  184. }
  185. switch base {
  186. case "o", "d", "x", "X":
  187. default:
  188. return "", 0, "bad base in $GENERATE"
  189. }
  190. offset, err := strconv.ParseInt(offStr, 10, 64)
  191. if err != nil {
  192. return "", 0, "bad offset in $GENERATE"
  193. }
  194. width, err := strconv.ParseInt(widthStr, 10, 64)
  195. if err != nil || width < 0 || width > 255 {
  196. return "", 0, "bad width in $GENERATE"
  197. }
  198. if width == 0 {
  199. return "%" + base, offset, ""
  200. }
  201. return "%0" + widthStr + base, offset, ""
  202. }