1package dns 2 3import ( 4 "fmt" 5 "strings" 6) 7 8// PrivateRdata is an interface used for implementing "Private Use" RR types, see 9// RFC 6895. This allows one to experiment with new RR types, without requesting an 10// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove. 11type PrivateRdata interface { 12 // String returns the text presentaton of the Rdata of the Private RR. 13 String() string 14 // Parse parses the Rdata of the private RR. 15 Parse([]string) error 16 // Pack is used when packing a private RR into a buffer. 17 Pack([]byte) (int, error) 18 // Unpack is used when unpacking a private RR from a buffer. 19 // TODO(miek): diff. signature than Pack, see edns0.go for instance. 20 Unpack([]byte) (int, error) 21 // Copy copies the Rdata. 22 Copy(PrivateRdata) error 23 // Len returns the length in octets of the Rdata. 24 Len() int 25} 26 27// PrivateRR represents an RR that uses a PrivateRdata user-defined type. 28// It mocks normal RRs and implements dns.RR interface. 29type PrivateRR struct { 30 Hdr RR_Header 31 Data PrivateRdata 32} 33 34func mkPrivateRR(rrtype uint16) *PrivateRR { 35 // Panics if RR is not an instance of PrivateRR. 36 rrfunc, ok := TypeToRR[rrtype] 37 if !ok { 38 panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype)) 39 } 40 41 anyrr := rrfunc() 42 switch rr := anyrr.(type) { 43 case *PrivateRR: 44 return rr 45 } 46 panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr)) 47} 48 49// Header return the RR header of r. 50func (r *PrivateRR) Header() *RR_Header { return &r.Hdr } 51 52func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() } 53 54// Private len and copy parts to satisfy RR interface. 55func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() } 56func (r *PrivateRR) copy() RR { 57 // make new RR like this: 58 rr := mkPrivateRR(r.Hdr.Rrtype) 59 rr.Hdr = r.Hdr 60 61 err := r.Data.Copy(rr.Data) 62 if err != nil { 63 panic("dns: got value that could not be used to copy Private rdata") 64 } 65 return rr 66} 67func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) { 68 off, err := r.Hdr.pack(msg, off, compression, compress) 69 if err != nil { 70 return off, err 71 } 72 headerEnd := off 73 n, err := r.Data.Pack(msg[off:]) 74 if err != nil { 75 return len(msg), err 76 } 77 off += n 78 r.Header().Rdlength = uint16(off - headerEnd) 79 return off, nil 80} 81 82// PrivateHandle registers a private resource record type. It requires 83// string and numeric representation of private RR type and generator function as argument. 84func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) { 85 rtypestr = strings.ToUpper(rtypestr) 86 87 TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} } 88 TypeToString[rtype] = rtypestr 89 StringToType[rtypestr] = rtype 90 91 typeToUnpack[rtype] = func(h RR_Header, msg []byte, off int) (RR, int, error) { 92 if noRdata(h) { 93 return &h, off, nil 94 } 95 var err error 96 97 rr := mkPrivateRR(h.Rrtype) 98 rr.Hdr = h 99 100 off1, err := rr.Data.Unpack(msg[off:]) 101 off += off1 102 if err != nil { 103 return rr, off, err 104 } 105 return rr, off, err 106 } 107 108 setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) { 109 rr := mkPrivateRR(h.Rrtype) 110 rr.Hdr = h 111 112 var l lex 113 text := make([]string, 0, 2) // could be 0..N elements, median is probably 1 114 Fetch: 115 for { 116 // TODO(miek): we could also be returning _QUOTE, this might or might not 117 // be an issue (basically parsing TXT becomes hard) 118 switch l = <-c; l.value { 119 case zNewline, zEOF: 120 break Fetch 121 case zString: 122 text = append(text, l.token) 123 } 124 } 125 126 err := rr.Data.Parse(text) 127 if err != nil { 128 return nil, &ParseError{f, err.Error(), l}, "" 129 } 130 131 return rr, nil, "" 132 } 133 134 typeToparserFunc[rtype] = parserFunc{setPrivateRR, true} 135} 136 137// PrivateHandleRemove removes defenitions required to support private RR type. 138func PrivateHandleRemove(rtype uint16) { 139 rtypestr, ok := TypeToString[rtype] 140 if ok { 141 delete(TypeToRR, rtype) 142 delete(TypeToString, rtype) 143 delete(typeToparserFunc, rtype) 144 delete(StringToType, rtypestr) 145 delete(typeToUnpack, rtype) 146 } 147 return 148} 149