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