1 package dns
2
3 import (
4 "bytes"
5 "fmt"
6 "io"
7 "strconv"
8 "strings"
9 )
10
11
12
13
14
15
16
17
18
19
20
21 func (zp *ZoneParser) generate(l lex) (RR, bool) {
22 token := l.token
23 step := int64(1)
24 if i := strings.IndexByte(token, '/'); i >= 0 {
25 if i+1 == len(token) {
26 return zp.setParseError("bad step in $GENERATE range", l)
27 }
28
29 s, err := strconv.ParseInt(token[i+1:], 10, 64)
30 if err != nil || s <= 0 {
31 return zp.setParseError("bad step in $GENERATE range", l)
32 }
33
34 step = s
35 token = token[:i]
36 }
37
38 startStr, endStr, ok := strings.Cut(token, "-")
39 if !ok {
40 return zp.setParseError("bad start-stop in $GENERATE range", l)
41 }
42
43 start, err := strconv.ParseInt(startStr, 10, 64)
44 if err != nil {
45 return zp.setParseError("bad start in $GENERATE range", l)
46 }
47
48 end, err := strconv.ParseInt(endStr, 10, 64)
49 if err != nil {
50 return zp.setParseError("bad stop in $GENERATE range", l)
51 }
52 if end < 0 || start < 0 || end < start || (end-start)/step > 65535 {
53 return zp.setParseError("bad range in $GENERATE range", l)
54 }
55
56
57 l, ok = zp.c.Next()
58 if !ok || l.value != zBlank {
59 return zp.setParseError("garbage after $GENERATE range", l)
60 }
61
62
63 var s string
64 for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
65 if l.err {
66 return zp.setParseError("bad data in $GENERATE directive", l)
67 }
68 if l.value == zNewline {
69 break
70 }
71
72 s += l.token
73 }
74
75 r := &generateReader{
76 s: s,
77
78 cur: start,
79 start: start,
80 end: end,
81 step: step,
82
83 file: zp.file,
84 lex: &l,
85 }
86 zp.sub = NewZoneParser(r, zp.origin, zp.file)
87 zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
88 zp.sub.generateDisallowed = true
89 zp.sub.SetDefaultTTL(defaultTtl)
90 return zp.subNext()
91 }
92
93 type generateReader struct {
94 s string
95 si int
96
97 cur int64
98 start int64
99 end int64
100 step int64
101
102 mod bytes.Buffer
103
104 escape bool
105
106 eof bool
107
108 file string
109 lex *lex
110 }
111
112 func (r *generateReader) parseError(msg string, end int) *ParseError {
113 r.eof = true
114
115 l := *r.lex
116 l.token = r.s[r.si-1 : end]
117 l.column += r.si
118
119 return &ParseError{r.file, msg, l}
120 }
121
122 func (r *generateReader) Read(p []byte) (int, error) {
123
124
125
126 panic("not implemented")
127 }
128
129 func (r *generateReader) ReadByte() (byte, error) {
130 if r.eof {
131 return 0, io.EOF
132 }
133 if r.mod.Len() > 0 {
134 return r.mod.ReadByte()
135 }
136
137 if r.si >= len(r.s) {
138 r.si = 0
139 r.cur += r.step
140
141 r.eof = r.cur > r.end || r.cur < 0
142 return '\n', nil
143 }
144
145 si := r.si
146 r.si++
147
148 switch r.s[si] {
149 case '\\':
150 if r.escape {
151 r.escape = false
152 return '\\', nil
153 }
154
155 r.escape = true
156 return r.ReadByte()
157 case '$':
158 if r.escape {
159 r.escape = false
160 return '$', nil
161 }
162
163 mod := "%d"
164
165 if si >= len(r.s)-1 {
166
167 fmt.Fprintf(&r.mod, mod, r.cur)
168 return r.mod.ReadByte()
169 }
170
171 if r.s[si+1] == '$' {
172 r.si++
173 return '$', nil
174 }
175
176 var offset int64
177
178
179 if r.s[si+1] == '{' {
180
181 sep := strings.Index(r.s[si+2:], "}")
182 if sep < 0 {
183 return 0, r.parseError("bad modifier in $GENERATE", len(r.s))
184 }
185
186 var errMsg string
187 mod, offset, errMsg = modToPrintf(r.s[si+2 : si+2+sep])
188 if errMsg != "" {
189 return 0, r.parseError(errMsg, si+3+sep)
190 }
191 if r.start+offset < 0 || r.end+offset > 1<<31-1 {
192 return 0, r.parseError("bad offset in $GENERATE", si+3+sep)
193 }
194
195 r.si += 2 + sep
196 }
197
198 fmt.Fprintf(&r.mod, mod, r.cur+offset)
199 return r.mod.ReadByte()
200 default:
201 if r.escape {
202 r.escape = false
203 return r.ReadByte()
204 }
205
206 return r.s[si], nil
207 }
208 }
209
210
211 func modToPrintf(s string) (string, int64, string) {
212
213
214 offStr, s, ok0 := strings.Cut(s, ",")
215 widthStr, s, ok1 := strings.Cut(s, ",")
216 base, _, ok2 := strings.Cut(s, ",")
217 if !ok0 {
218 widthStr = "0"
219 }
220 if !ok1 {
221 base = "d"
222 }
223 if ok2 {
224 return "", 0, "bad modifier in $GENERATE"
225 }
226
227 switch base {
228 case "o", "d", "x", "X":
229 default:
230 return "", 0, "bad base in $GENERATE"
231 }
232
233 offset, err := strconv.ParseInt(offStr, 10, 64)
234 if err != nil {
235 return "", 0, "bad offset in $GENERATE"
236 }
237
238 width, err := strconv.ParseUint(widthStr, 10, 8)
239 if err != nil {
240 return "", 0, "bad width in $GENERATE"
241 }
242
243 if width == 0 {
244 return "%" + base, offset, ""
245 }
246
247 return "%0" + widthStr + base, offset, ""
248 }
249
View as plain text