1 package dns
2
3 import (
4 "bufio"
5 "fmt"
6 "io"
7 "os"
8 "path/filepath"
9 "strconv"
10 "strings"
11 )
12
13 const maxTok = 512
14
15
16
17 const maxIncludeDepth = 7
18
19
20
21
22
23
24
25 const (
26
27 zEOF = iota
28 zString
29 zBlank
30 zQuote
31 zNewline
32 zRrtpe
33 zOwner
34 zClass
35 zDirOrigin
36 zDirTTL
37 zDirInclude
38 zDirGenerate
39
40
41 zValue
42 zKey
43
44 zExpectOwnerDir
45 zExpectOwnerBl
46 zExpectAny
47 zExpectAnyNoClass
48 zExpectAnyNoClassBl
49 zExpectAnyNoTTL
50 zExpectAnyNoTTLBl
51 zExpectRrtype
52 zExpectRrtypeBl
53 zExpectRdata
54 zExpectDirTTLBl
55 zExpectDirTTL
56 zExpectDirOriginBl
57 zExpectDirOrigin
58 zExpectDirIncludeBl
59 zExpectDirInclude
60 zExpectDirGenerate
61 zExpectDirGenerateBl
62 )
63
64
65
66 type ParseError struct {
67 file string
68 err string
69 lex lex
70 }
71
72 func (e *ParseError) Error() (s string) {
73 if e.file != "" {
74 s = e.file + ": "
75 }
76 s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
77 strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
78 return
79 }
80
81 type lex struct {
82 token string
83 err bool
84 value uint8
85 torc uint16
86 line int
87 column int
88 }
89
90
91 type ttlState struct {
92 ttl uint32
93 isByDirective bool
94 }
95
96
97
98
99
100
101
102 func NewRR(s string) (RR, error) {
103 if len(s) > 0 && s[len(s)-1] != '\n' {
104 return ReadRR(strings.NewReader(s+"\n"), "")
105 }
106 return ReadRR(strings.NewReader(s), "")
107 }
108
109
110
111
112
113
114
115 func ReadRR(r io.Reader, file string) (RR, error) {
116 zp := NewZoneParser(r, ".", file)
117 zp.SetDefaultTTL(defaultTtl)
118 zp.SetIncludeAllowed(true)
119 rr, _ := zp.Next()
120 return rr, zp.Err()
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 type ZoneParser struct {
157 c *zlexer
158
159 parseErr *ParseError
160
161 origin string
162 file string
163
164 defttl *ttlState
165
166 h RR_Header
167
168
169
170
171 sub *ZoneParser
172 osFile *os.File
173
174 includeDepth uint8
175
176 includeAllowed bool
177 generateDisallowed bool
178 }
179
180
181
182
183
184
185
186 func NewZoneParser(r io.Reader, origin, file string) *ZoneParser {
187 var pe *ParseError
188 if origin != "" {
189 origin = Fqdn(origin)
190 if _, ok := IsDomainName(origin); !ok {
191 pe = &ParseError{file, "bad initial origin name", lex{}}
192 }
193 }
194
195 return &ZoneParser{
196 c: newZLexer(r),
197
198 parseErr: pe,
199
200 origin: origin,
201 file: file,
202 }
203 }
204
205
206 func (zp *ZoneParser) SetDefaultTTL(ttl uint32) {
207 zp.defttl = &ttlState{ttl, false}
208 }
209
210
211
212
213
214
215
216
217
218
219 func (zp *ZoneParser) SetIncludeAllowed(v bool) {
220 zp.includeAllowed = v
221 }
222
223
224
225 func (zp *ZoneParser) Err() error {
226 if zp.parseErr != nil {
227 return zp.parseErr
228 }
229
230 if zp.sub != nil {
231 if err := zp.sub.Err(); err != nil {
232 return err
233 }
234 }
235
236 return zp.c.Err()
237 }
238
239 func (zp *ZoneParser) setParseError(err string, l lex) (RR, bool) {
240 zp.parseErr = &ParseError{zp.file, err, l}
241 return nil, false
242 }
243
244
245
246 func (zp *ZoneParser) Comment() string {
247 if zp.parseErr != nil {
248 return ""
249 }
250
251 if zp.sub != nil {
252 return zp.sub.Comment()
253 }
254
255 return zp.c.Comment()
256 }
257
258 func (zp *ZoneParser) subNext() (RR, bool) {
259 if rr, ok := zp.sub.Next(); ok {
260 return rr, true
261 }
262
263 if zp.sub.osFile != nil {
264 zp.sub.osFile.Close()
265 zp.sub.osFile = nil
266 }
267
268 if zp.sub.Err() != nil {
269
270 return nil, false
271 }
272
273 zp.sub = nil
274 return zp.Next()
275 }
276
277
278
279
280
281
282 func (zp *ZoneParser) Next() (RR, bool) {
283 if zp.parseErr != nil {
284 return nil, false
285 }
286 if zp.sub != nil {
287 return zp.subNext()
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301
302 st := zExpectOwnerDir
303 h := &zp.h
304
305 for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
306
307 if l.err {
308 return zp.setParseError(l.token, l)
309 }
310
311 switch st {
312 case zExpectOwnerDir:
313
314 if zp.defttl != nil {
315 h.Ttl = zp.defttl.ttl
316 }
317
318 h.Class = ClassINET
319
320 switch l.value {
321 case zNewline:
322 st = zExpectOwnerDir
323 case zOwner:
324 name, ok := toAbsoluteName(l.token, zp.origin)
325 if !ok {
326 return zp.setParseError("bad owner name", l)
327 }
328
329 h.Name = name
330
331 st = zExpectOwnerBl
332 case zDirTTL:
333 st = zExpectDirTTLBl
334 case zDirOrigin:
335 st = zExpectDirOriginBl
336 case zDirInclude:
337 st = zExpectDirIncludeBl
338 case zDirGenerate:
339 st = zExpectDirGenerateBl
340 case zRrtpe:
341 h.Rrtype = l.torc
342
343 st = zExpectRdata
344 case zClass:
345 h.Class = l.torc
346
347 st = zExpectAnyNoClassBl
348 case zBlank:
349
350
351 case zString:
352 ttl, ok := stringToTTL(l.token)
353 if !ok {
354 return zp.setParseError("not a TTL", l)
355 }
356
357 h.Ttl = ttl
358
359 if zp.defttl == nil || !zp.defttl.isByDirective {
360 zp.defttl = &ttlState{ttl, false}
361 }
362
363 st = zExpectAnyNoTTLBl
364 default:
365 return zp.setParseError("syntax error at beginning", l)
366 }
367 case zExpectDirIncludeBl:
368 if l.value != zBlank {
369 return zp.setParseError("no blank after $INCLUDE-directive", l)
370 }
371
372 st = zExpectDirInclude
373 case zExpectDirInclude:
374 if l.value != zString {
375 return zp.setParseError("expecting $INCLUDE value, not this...", l)
376 }
377
378 neworigin := zp.origin
379 switch l, _ := zp.c.Next(); l.value {
380 case zBlank:
381 l, _ := zp.c.Next()
382 if l.value == zString {
383 name, ok := toAbsoluteName(l.token, zp.origin)
384 if !ok {
385 return zp.setParseError("bad origin name", l)
386 }
387
388 neworigin = name
389 }
390 case zNewline, zEOF:
391
392 default:
393 return zp.setParseError("garbage after $INCLUDE", l)
394 }
395
396 if !zp.includeAllowed {
397 return zp.setParseError("$INCLUDE directive not allowed", l)
398 }
399 if zp.includeDepth >= maxIncludeDepth {
400 return zp.setParseError("too deeply nested $INCLUDE", l)
401 }
402
403
404 includePath := l.token
405 if !filepath.IsAbs(includePath) {
406 includePath = filepath.Join(filepath.Dir(zp.file), includePath)
407 }
408
409 r1, e1 := os.Open(includePath)
410 if e1 != nil {
411 var as string
412 if !filepath.IsAbs(l.token) {
413 as = fmt.Sprintf(" as `%s'", includePath)
414 }
415
416 msg := fmt.Sprintf("failed to open `%s'%s: %v", l.token, as, e1)
417 return zp.setParseError(msg, l)
418 }
419
420 zp.sub = NewZoneParser(r1, neworigin, includePath)
421 zp.sub.defttl, zp.sub.includeDepth, zp.sub.osFile = zp.defttl, zp.includeDepth+1, r1
422 zp.sub.SetIncludeAllowed(true)
423 return zp.subNext()
424 case zExpectDirTTLBl:
425 if l.value != zBlank {
426 return zp.setParseError("no blank after $TTL-directive", l)
427 }
428
429 st = zExpectDirTTL
430 case zExpectDirTTL:
431 if l.value != zString {
432 return zp.setParseError("expecting $TTL value, not this...", l)
433 }
434
435 if err := slurpRemainder(zp.c); err != nil {
436 return zp.setParseError(err.err, err.lex)
437 }
438
439 ttl, ok := stringToTTL(l.token)
440 if !ok {
441 return zp.setParseError("expecting $TTL value, not this...", l)
442 }
443
444 zp.defttl = &ttlState{ttl, true}
445
446 st = zExpectOwnerDir
447 case zExpectDirOriginBl:
448 if l.value != zBlank {
449 return zp.setParseError("no blank after $ORIGIN-directive", l)
450 }
451
452 st = zExpectDirOrigin
453 case zExpectDirOrigin:
454 if l.value != zString {
455 return zp.setParseError("expecting $ORIGIN value, not this...", l)
456 }
457
458 if err := slurpRemainder(zp.c); err != nil {
459 return zp.setParseError(err.err, err.lex)
460 }
461
462 name, ok := toAbsoluteName(l.token, zp.origin)
463 if !ok {
464 return zp.setParseError("bad origin name", l)
465 }
466
467 zp.origin = name
468
469 st = zExpectOwnerDir
470 case zExpectDirGenerateBl:
471 if l.value != zBlank {
472 return zp.setParseError("no blank after $GENERATE-directive", l)
473 }
474
475 st = zExpectDirGenerate
476 case zExpectDirGenerate:
477 if zp.generateDisallowed {
478 return zp.setParseError("nested $GENERATE directive not allowed", l)
479 }
480 if l.value != zString {
481 return zp.setParseError("expecting $GENERATE value, not this...", l)
482 }
483
484 return zp.generate(l)
485 case zExpectOwnerBl:
486 if l.value != zBlank {
487 return zp.setParseError("no blank after owner", l)
488 }
489
490 st = zExpectAny
491 case zExpectAny:
492 switch l.value {
493 case zRrtpe:
494 if zp.defttl == nil {
495 return zp.setParseError("missing TTL with no previous value", l)
496 }
497
498 h.Rrtype = l.torc
499
500 st = zExpectRdata
501 case zClass:
502 h.Class = l.torc
503
504 st = zExpectAnyNoClassBl
505 case zString:
506 ttl, ok := stringToTTL(l.token)
507 if !ok {
508 return zp.setParseError("not a TTL", l)
509 }
510
511 h.Ttl = ttl
512
513 if zp.defttl == nil || !zp.defttl.isByDirective {
514 zp.defttl = &ttlState{ttl, false}
515 }
516
517 st = zExpectAnyNoTTLBl
518 default:
519 return zp.setParseError("expecting RR type, TTL or class, not this...", l)
520 }
521 case zExpectAnyNoClassBl:
522 if l.value != zBlank {
523 return zp.setParseError("no blank before class", l)
524 }
525
526 st = zExpectAnyNoClass
527 case zExpectAnyNoTTLBl:
528 if l.value != zBlank {
529 return zp.setParseError("no blank before TTL", l)
530 }
531
532 st = zExpectAnyNoTTL
533 case zExpectAnyNoTTL:
534 switch l.value {
535 case zClass:
536 h.Class = l.torc
537
538 st = zExpectRrtypeBl
539 case zRrtpe:
540 h.Rrtype = l.torc
541
542 st = zExpectRdata
543 default:
544 return zp.setParseError("expecting RR type or class, not this...", l)
545 }
546 case zExpectAnyNoClass:
547 switch l.value {
548 case zString:
549 ttl, ok := stringToTTL(l.token)
550 if !ok {
551 return zp.setParseError("not a TTL", l)
552 }
553
554 h.Ttl = ttl
555
556 if zp.defttl == nil || !zp.defttl.isByDirective {
557 zp.defttl = &ttlState{ttl, false}
558 }
559
560 st = zExpectRrtypeBl
561 case zRrtpe:
562 h.Rrtype = l.torc
563
564 st = zExpectRdata
565 default:
566 return zp.setParseError("expecting RR type or TTL, not this...", l)
567 }
568 case zExpectRrtypeBl:
569 if l.value != zBlank {
570 return zp.setParseError("no blank before RR type", l)
571 }
572
573 st = zExpectRrtype
574 case zExpectRrtype:
575 if l.value != zRrtpe {
576 return zp.setParseError("unknown RR type", l)
577 }
578
579 h.Rrtype = l.torc
580
581 st = zExpectRdata
582 case zExpectRdata:
583 var (
584 rr RR
585 parseAsRFC3597 bool
586 )
587 if newFn, ok := TypeToRR[h.Rrtype]; ok {
588 rr = newFn()
589 *rr.Header() = *h
590
591
592
593
594
595
596
597 if zp.c.Peek().token == "\\#" {
598 parseAsRFC3597 = true
599 }
600 } else {
601 rr = &RFC3597{Hdr: *h}
602 }
603
604 _, isPrivate := rr.(*PrivateRR)
605 if !isPrivate && zp.c.Peek().token == "" {
606
607
608 if err := slurpRemainder(zp.c); err != nil {
609 return zp.setParseError(err.err, err.lex)
610 }
611
612 return rr, true
613 } else if l.value == zNewline {
614 return zp.setParseError("unexpected newline", l)
615 }
616
617 parseAsRR := rr
618 if parseAsRFC3597 {
619 parseAsRR = &RFC3597{Hdr: *h}
620 }
621
622 if err := parseAsRR.parse(zp.c, zp.origin); err != nil {
623
624
625
626
627
628
629 if err.lex == (lex{}) {
630 return zp.setParseError(err.err, l)
631 }
632
633 return zp.setParseError(err.err, err.lex)
634 }
635
636 if parseAsRFC3597 {
637 err := parseAsRR.(*RFC3597).fromRFC3597(rr)
638 if err != nil {
639 return zp.setParseError(err.Error(), l)
640 }
641 }
642
643 return rr, true
644 }
645 }
646
647
648
649 return nil, false
650 }
651
652 type zlexer struct {
653 br io.ByteReader
654
655 readErr error
656
657 line int
658 column int
659
660 comBuf string
661 comment string
662
663 l lex
664 cachedL *lex
665
666 brace int
667 quote bool
668 space bool
669 commt bool
670 rrtype bool
671 owner bool
672
673 nextL bool
674
675 eol bool
676 }
677
678 func newZLexer(r io.Reader) *zlexer {
679 br, ok := r.(io.ByteReader)
680 if !ok {
681 br = bufio.NewReaderSize(r, 1024)
682 }
683
684 return &zlexer{
685 br: br,
686
687 line: 1,
688
689 owner: true,
690 }
691 }
692
693 func (zl *zlexer) Err() error {
694 if zl.readErr == io.EOF {
695 return nil
696 }
697
698 return zl.readErr
699 }
700
701
702 func (zl *zlexer) readByte() (byte, bool) {
703 if zl.readErr != nil {
704 return 0, false
705 }
706
707 c, err := zl.br.ReadByte()
708 if err != nil {
709 zl.readErr = err
710 return 0, false
711 }
712
713
714
715 if zl.eol {
716 zl.line++
717 zl.column = 0
718 zl.eol = false
719 }
720
721 if c == '\n' {
722 zl.eol = true
723 } else {
724 zl.column++
725 }
726
727 return c, true
728 }
729
730 func (zl *zlexer) Peek() lex {
731 if zl.nextL {
732 return zl.l
733 }
734
735 l, ok := zl.Next()
736 if !ok {
737 return l
738 }
739
740 if zl.nextL {
741
742 zl.cachedL = &l
743 } else {
744
745 zl.nextL = true
746 }
747
748 return l
749 }
750
751 func (zl *zlexer) Next() (lex, bool) {
752 l := &zl.l
753 switch {
754 case zl.cachedL != nil:
755 l, zl.cachedL = zl.cachedL, nil
756 return *l, true
757 case zl.nextL:
758 zl.nextL = false
759 return *l, true
760 case l.err:
761
762 return lex{value: zEOF}, false
763 }
764
765 var (
766 str = make([]byte, maxTok)
767 com = make([]byte, maxTok)
768
769 stri int
770 comi int
771
772 escape bool
773 )
774
775 if zl.comBuf != "" {
776 comi = copy(com[:], zl.comBuf)
777 zl.comBuf = ""
778 }
779
780 zl.comment = ""
781
782 for x, ok := zl.readByte(); ok; x, ok = zl.readByte() {
783 l.line, l.column = zl.line, zl.column
784
785 if stri >= len(str) {
786
787 str = append(str[:], make([]byte, maxTok)...)
788 }
789 if comi >= len(com) {
790
791 com = append(com[:], make([]byte, maxTok)...)
792 }
793
794 switch x {
795 case ' ', '\t':
796 if escape || zl.quote {
797
798 str[stri] = x
799 stri++
800
801 escape = false
802 break
803 }
804
805 if zl.commt {
806 com[comi] = x
807 comi++
808 break
809 }
810
811 var retL lex
812 if stri == 0 {
813
814 } else if zl.owner {
815
816 l.value = zOwner
817 l.token = string(str[:stri])
818
819
820 switch strings.ToUpper(l.token) {
821 case "$TTL":
822 l.value = zDirTTL
823 case "$ORIGIN":
824 l.value = zDirOrigin
825 case "$INCLUDE":
826 l.value = zDirInclude
827 case "$GENERATE":
828 l.value = zDirGenerate
829 }
830
831 retL = *l
832 } else {
833 l.value = zString
834 l.token = string(str[:stri])
835
836 if !zl.rrtype {
837 tokenUpper := strings.ToUpper(l.token)
838 if t, ok := StringToType[tokenUpper]; ok {
839 l.value = zRrtpe
840 l.torc = t
841
842 zl.rrtype = true
843 } else if strings.HasPrefix(tokenUpper, "TYPE") {
844 t, ok := typeToInt(l.token)
845 if !ok {
846 l.token = "unknown RR type"
847 l.err = true
848 return *l, true
849 }
850
851 l.value = zRrtpe
852 l.torc = t
853
854 zl.rrtype = true
855 }
856
857 if t, ok := StringToClass[tokenUpper]; ok {
858 l.value = zClass
859 l.torc = t
860 } else if strings.HasPrefix(tokenUpper, "CLASS") {
861 t, ok := classToInt(l.token)
862 if !ok {
863 l.token = "unknown class"
864 l.err = true
865 return *l, true
866 }
867
868 l.value = zClass
869 l.torc = t
870 }
871 }
872
873 retL = *l
874 }
875
876 zl.owner = false
877
878 if !zl.space {
879 zl.space = true
880
881 l.value = zBlank
882 l.token = " "
883
884 if retL == (lex{}) {
885 return *l, true
886 }
887
888 zl.nextL = true
889 }
890
891 if retL != (lex{}) {
892 return retL, true
893 }
894 case ';':
895 if escape || zl.quote {
896
897 str[stri] = x
898 stri++
899
900 escape = false
901 break
902 }
903
904 zl.commt = true
905 zl.comBuf = ""
906
907 if comi > 1 {
908
909
910 com[comi] = ' '
911 comi++
912 if comi >= len(com) {
913 l.token = "comment length insufficient for parsing"
914 l.err = true
915 return *l, true
916 }
917 }
918
919 com[comi] = ';'
920 comi++
921
922 if stri > 0 {
923 zl.comBuf = string(com[:comi])
924
925 l.value = zString
926 l.token = string(str[:stri])
927 return *l, true
928 }
929 case '\r':
930 escape = false
931
932 if zl.quote {
933 str[stri] = x
934 stri++
935 }
936
937
938 case '\n':
939 escape = false
940
941
942 if zl.quote {
943 str[stri] = x
944 stri++
945 break
946 }
947
948 if zl.commt {
949
950 zl.commt = false
951 zl.rrtype = false
952
953
954 if zl.brace == 0 {
955 zl.owner = true
956
957 l.value = zNewline
958 l.token = "\n"
959 zl.comment = string(com[:comi])
960 return *l, true
961 }
962
963 zl.comBuf = string(com[:comi])
964 break
965 }
966
967 if zl.brace == 0 {
968
969 var retL lex
970 if stri != 0 {
971 l.value = zString
972 l.token = string(str[:stri])
973
974 if !zl.rrtype {
975 tokenUpper := strings.ToUpper(l.token)
976 if t, ok := StringToType[tokenUpper]; ok {
977 zl.rrtype = true
978
979 l.value = zRrtpe
980 l.torc = t
981 }
982 }
983
984 retL = *l
985 }
986
987 l.value = zNewline
988 l.token = "\n"
989
990 zl.comment = zl.comBuf
991 zl.comBuf = ""
992 zl.rrtype = false
993 zl.owner = true
994
995 if retL != (lex{}) {
996 zl.nextL = true
997 return retL, true
998 }
999
1000 return *l, true
1001 }
1002 case '\\':
1003
1004 if zl.commt {
1005 com[comi] = x
1006 comi++
1007 break
1008 }
1009
1010
1011 if escape {
1012 str[stri] = x
1013 stri++
1014
1015 escape = false
1016 break
1017 }
1018
1019
1020 str[stri] = x
1021 stri++
1022
1023 escape = true
1024 case '"':
1025 if zl.commt {
1026 com[comi] = x
1027 comi++
1028 break
1029 }
1030
1031 if escape {
1032 str[stri] = x
1033 stri++
1034
1035 escape = false
1036 break
1037 }
1038
1039 zl.space = false
1040
1041
1042 var retL lex
1043 if stri != 0 {
1044 l.value = zString
1045 l.token = string(str[:stri])
1046
1047 retL = *l
1048 }
1049
1050
1051 l.value = zQuote
1052 l.token = "\""
1053
1054 zl.quote = !zl.quote
1055
1056 if retL != (lex{}) {
1057 zl.nextL = true
1058 return retL, true
1059 }
1060
1061 return *l, true
1062 case '(', ')':
1063 if zl.commt {
1064 com[comi] = x
1065 comi++
1066 break
1067 }
1068
1069 if escape || zl.quote {
1070
1071 str[stri] = x
1072 stri++
1073
1074 escape = false
1075 break
1076 }
1077
1078 switch x {
1079 case ')':
1080 zl.brace--
1081
1082 if zl.brace < 0 {
1083 l.token = "extra closing brace"
1084 l.err = true
1085 return *l, true
1086 }
1087 case '(':
1088 zl.brace++
1089 }
1090 default:
1091 escape = false
1092
1093 if zl.commt {
1094 com[comi] = x
1095 comi++
1096 break
1097 }
1098
1099 str[stri] = x
1100 stri++
1101
1102 zl.space = false
1103 }
1104 }
1105
1106 if zl.readErr != nil && zl.readErr != io.EOF {
1107
1108 return lex{value: zEOF}, false
1109 }
1110
1111 var retL lex
1112 if stri > 0 {
1113
1114 l.value = zString
1115 l.token = string(str[:stri])
1116 retL = *l
1117
1118 if comi <= 0 {
1119 return retL, true
1120 }
1121 }
1122
1123 if comi > 0 {
1124
1125 l.value = zNewline
1126 l.token = "\n"
1127 zl.comment = string(com[:comi])
1128
1129 if retL != (lex{}) {
1130 zl.nextL = true
1131 return retL, true
1132 }
1133
1134 return *l, true
1135 }
1136
1137 if zl.brace != 0 {
1138 l.token = "unbalanced brace"
1139 l.err = true
1140 return *l, true
1141 }
1142
1143 return lex{value: zEOF}, false
1144 }
1145
1146 func (zl *zlexer) Comment() string {
1147 if zl.l.err {
1148 return ""
1149 }
1150
1151 return zl.comment
1152 }
1153
1154
1155 func classToInt(token string) (uint16, bool) {
1156 offset := 5
1157 if len(token) < offset+1 {
1158 return 0, false
1159 }
1160 class, err := strconv.ParseUint(token[offset:], 10, 16)
1161 if err != nil {
1162 return 0, false
1163 }
1164 return uint16(class), true
1165 }
1166
1167
1168 func typeToInt(token string) (uint16, bool) {
1169 offset := 4
1170 if len(token) < offset+1 {
1171 return 0, false
1172 }
1173 typ, err := strconv.ParseUint(token[offset:], 10, 16)
1174 if err != nil {
1175 return 0, false
1176 }
1177 return uint16(typ), true
1178 }
1179
1180
1181 func stringToTTL(token string) (uint32, bool) {
1182 var s, i uint32
1183 for _, c := range token {
1184 switch c {
1185 case 's', 'S':
1186 s += i
1187 i = 0
1188 case 'm', 'M':
1189 s += i * 60
1190 i = 0
1191 case 'h', 'H':
1192 s += i * 60 * 60
1193 i = 0
1194 case 'd', 'D':
1195 s += i * 60 * 60 * 24
1196 i = 0
1197 case 'w', 'W':
1198 s += i * 60 * 60 * 24 * 7
1199 i = 0
1200 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
1201 i *= 10
1202 i += uint32(c) - '0'
1203 default:
1204 return 0, false
1205 }
1206 }
1207 return s + i, true
1208 }
1209
1210
1211
1212
1213 func stringToCm(token string) (e, m uint8, ok bool) {
1214 if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
1215 token = token[0 : len(token)-1]
1216 }
1217
1218 var (
1219 meters, cmeters, val int
1220 err error
1221 )
1222 mStr, cmStr, hasCM := strings.Cut(token, ".")
1223 if hasCM {
1224
1225
1226
1227 cmeters, err = strconv.Atoi(cmStr)
1228 if err != nil || len(cmStr) > 2 || cmStr[0] < '0' || cmStr[0] > '9' {
1229 return
1230 }
1231 if len(cmStr) == 1 {
1232
1233 cmeters *= 10
1234 }
1235 }
1236
1237 if !hasCM || mStr != "" {
1238 meters, err = strconv.Atoi(mStr)
1239
1240 if err != nil || mStr[0] < '0' || mStr[0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) {
1241 return
1242 }
1243 }
1244
1245 if meters > 0 {
1246 e = 2
1247 val = meters
1248 } else {
1249 e = 0
1250 val = cmeters
1251 }
1252 for val >= 10 {
1253 e++
1254 val /= 10
1255 }
1256 return e, uint8(val), true
1257 }
1258
1259 func toAbsoluteName(name, origin string) (absolute string, ok bool) {
1260
1261 if name == "@" {
1262
1263 if origin == "" {
1264 return "", false
1265 }
1266 return origin, true
1267 }
1268
1269
1270 _, ok = IsDomainName(name)
1271 if !ok || name == "" {
1272 return "", false
1273 }
1274
1275
1276 if IsFqdn(name) {
1277 return name, true
1278 }
1279
1280
1281 if origin == "" {
1282 return "", false
1283 }
1284 return appendOrigin(name, origin), true
1285 }
1286
1287 func appendOrigin(name, origin string) string {
1288 if origin == "." {
1289 return name + origin
1290 }
1291 return name + "." + origin
1292 }
1293
1294
1295 func locCheckNorth(token string, latitude uint32) (uint32, bool) {
1296 if latitude > 90*1000*60*60 {
1297 return latitude, false
1298 }
1299 switch token {
1300 case "n", "N":
1301 return LOC_EQUATOR + latitude, true
1302 case "s", "S":
1303 return LOC_EQUATOR - latitude, true
1304 }
1305 return latitude, false
1306 }
1307
1308
1309 func locCheckEast(token string, longitude uint32) (uint32, bool) {
1310 if longitude > 180*1000*60*60 {
1311 return longitude, false
1312 }
1313 switch token {
1314 case "e", "E":
1315 return LOC_EQUATOR + longitude, true
1316 case "w", "W":
1317 return LOC_EQUATOR - longitude, true
1318 }
1319 return longitude, false
1320 }
1321
1322
1323 func slurpRemainder(c *zlexer) *ParseError {
1324 l, _ := c.Next()
1325 switch l.value {
1326 case zBlank:
1327 l, _ = c.Next()
1328 if l.value != zNewline && l.value != zEOF {
1329 return &ParseError{"", "garbage after rdata", l}
1330 }
1331 case zNewline:
1332 case zEOF:
1333 default:
1334 return &ParseError{"", "garbage after rdata", l}
1335 }
1336 return nil
1337 }
1338
1339
1340
1341 func stringToNodeID(l lex) (uint64, *ParseError) {
1342 if len(l.token) < 19 {
1343 return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
1344 }
1345
1346 if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
1347 return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
1348 }
1349 s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
1350 u, err := strconv.ParseUint(s, 16, 64)
1351 if err != nil {
1352 return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
1353 }
1354 return u, nil
1355 }
1356
View as plain text