]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/dnsmasq/019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
bird: New package
[ipfire-2.x.git] / src / patches / dnsmasq / 019-Generalise_RR-filtering_code_for_use_with_EDNS0.patch
CommitLineData
fbcc3cb7
MF
1From c2bcd1e183bcc5fdd63811c045355fc57e36ecfd Mon Sep 17 00:00:00 2001
2From: Simon Kelley <simon@thekelleys.org.uk>
3Date: Tue, 15 Dec 2015 17:25:21 +0000
4Subject: [PATCH] Generalise RR-filtering code, for use with EDNS0.
5
6---
7 Makefile | 3 +-
8 bld/Android.mk | 2 +-
9 src/dnsmasq.h | 5 +
10 src/dnssec.c | 307 +-------------------------------------------------
11 src/forward.c | 2 +-
12 src/rrfilter.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 6 files changed, 349 insertions(+), 309 deletions(-)
14 create mode 100644 src/rrfilter.c
15
16diff --git a/Makefile b/Makefile
17index 4c87ea9..b664160 100644
18--- a/Makefile
19+++ b/Makefile
20@@ -73,7 +73,8 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
21 dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
22 helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
23 dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
24- domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o
25+ domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
26+ poll.o rrfilter.o
27
28 hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
29 dns-protocol.h radv-protocol.h ip6addr.h
30diff --git a/bld/Android.mk b/bld/Android.mk
31index 5364ee7..67b9c4b 100644
32--- a/bld/Android.mk
33+++ b/bld/Android.mk
34@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
35 dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
36 radv.c slaac.c auth.c ipset.c domain.c \
37 dnssec.c dnssec-openssl.c blockdata.c tables.c \
38- loop.c inotify.c poll.c
39+ loop.c inotify.c poll.c rrfilter.c
40
41 LOCAL_MODULE := dnsmasq
42
43diff --git a/src/dnsmasq.h b/src/dnsmasq.h
44index 4344cae..39a930c 100644
45--- a/src/dnsmasq.h
46+++ b/src/dnsmasq.h
47@@ -1513,3 +1513,8 @@ int poll_check(int fd, short event);
48 void poll_listen(int fd, short event);
49 int do_poll(int timeout);
50
51+/* rrfilter.c */
52+size_t rrfilter(struct dns_header *header, size_t plen, int mode);
53+u16 *rrfilter_desc(int type);
54+int expand_workspace(unsigned char ***wkspc, int *szp, int new);
55+
56diff --git a/src/dnssec.c b/src/dnssec.c
57index 359231f..fa3eb81 100644
58--- a/src/dnssec.c
59+++ b/src/dnssec.c
60@@ -507,50 +507,6 @@ static int check_date_range(unsigned long date_start, unsigned long date_end)
61 && serial_compare_32(curtime, date_end) == SERIAL_LT;
62 }
63
64-static u16 *get_desc(int type)
65-{
66- /* List of RRtypes which include domains in the data.
67- 0 -> domain
68- integer -> no of plain bytes
69- -1 -> end
70-
71- zero is not a valid RRtype, so the final entry is returned for
72- anything which needs no mangling.
73- */
74-
75- static u16 rr_desc[] =
76- {
77- T_NS, 0, -1,
78- T_MD, 0, -1,
79- T_MF, 0, -1,
80- T_CNAME, 0, -1,
81- T_SOA, 0, 0, -1,
82- T_MB, 0, -1,
83- T_MG, 0, -1,
84- T_MR, 0, -1,
85- T_PTR, 0, -1,
86- T_MINFO, 0, 0, -1,
87- T_MX, 2, 0, -1,
88- T_RP, 0, 0, -1,
89- T_AFSDB, 2, 0, -1,
90- T_RT, 2, 0, -1,
91- T_SIG, 18, 0, -1,
92- T_PX, 2, 0, 0, -1,
93- T_NXT, 0, -1,
94- T_KX, 2, 0, -1,
95- T_SRV, 6, 0, -1,
96- T_DNAME, 0, -1,
97- 0, -1 /* wildcard/catchall */
98- };
99-
100- u16 *p = rr_desc;
101-
102- while (*p != type && *p != 0)
103- while (*p++ != (u16)-1);
104-
105- return p+1;
106-}
107-
108 /* Return bytes of canonicalised rdata, when the return value is zero, the remaining
109 data, pointed to by *p, should be used raw. */
110 static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
111@@ -594,34 +550,6 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
112 }
113 }
114
115-static int expand_workspace(unsigned char ***wkspc, int *szp, int new)
116-{
117- unsigned char **p;
118- int old = *szp;
119-
120- if (old >= new+1)
121- return 1;
122-
123- if (new >= 100)
124- return 0;
125-
126- new += 5;
127-
128- if (!(p = whine_malloc(new * sizeof(unsigned char **))))
129- return 0;
130-
131- if (old != 0 && *wkspc)
132- {
133- memcpy(p, *wkspc, old * sizeof(unsigned char **));
134- free(*wkspc);
135- }
136-
137- *wkspc = p;
138- *szp = new;
139-
140- return 1;
141-}
142-
143 /* Bubble sort the RRset into the canonical order.
144 Note that the byte-streams from two RRs may get unsynced: consider
145 RRs which have two domain-names at the start and then other data.
146@@ -849,7 +777,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
147 int rdlen, j, name_labels;
148 struct crec *crecp = NULL;
149 int algo, labels, orig_ttl, key_tag;
150- u16 *rr_desc = get_desc(type);
151+ u16 *rr_desc = rrfilter_desc(type);
152
153 if (wildcard_out)
154 *wildcard_out = NULL;
155@@ -2266,239 +2194,6 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
156 return ret;
157 }
158
159-/* Go through a domain name, find "pointers" and fix them up based on how many bytes
160- we've chopped out of the packet, or check they don't point into an elided part. */
161-static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
162-{
163- unsigned char *ansp = *namep;
164-
165- while(1)
166- {
167- unsigned int label_type;
168-
169- if (!CHECK_LEN(header, ansp, plen, 1))
170- return 0;
171-
172- label_type = (*ansp) & 0xc0;
173-
174- if (label_type == 0xc0)
175- {
176- /* pointer for compression. */
177- unsigned int offset;
178- int i;
179- unsigned char *p;
180-
181- if (!CHECK_LEN(header, ansp, plen, 2))
182- return 0;
183-
184- offset = ((*ansp++) & 0x3f) << 8;
185- offset |= *ansp++;
186-
187- p = offset + (unsigned char *)header;
188-
189- for (i = 0; i < rr_count; i++)
190- if (p < rrs[i])
191- break;
192- else
193- if (i & 1)
194- offset -= rrs[i] - rrs[i-1];
195-
196- /* does the pointer end up in an elided RR? */
197- if (i & 1)
198- return 0;
199-
200- /* No, scale the pointer */
201- if (fixup)
202- {
203- ansp -= 2;
204- *ansp++ = (offset >> 8) | 0xc0;
205- *ansp++ = offset & 0xff;
206- }
207- break;
208- }
209- else if (label_type == 0x80)
210- return 0; /* reserved */
211- else if (label_type == 0x40)
212- {
213- /* Extended label type */
214- unsigned int count;
215-
216- if (!CHECK_LEN(header, ansp, plen, 2))
217- return 0;
218-
219- if (((*ansp++) & 0x3f) != 1)
220- return 0; /* we only understand bitstrings */
221-
222- count = *(ansp++); /* Bits in bitstring */
223-
224- if (count == 0) /* count == 0 means 256 bits */
225- ansp += 32;
226- else
227- ansp += ((count-1)>>3)+1;
228- }
229- else
230- { /* label type == 0 Bottom six bits is length */
231- unsigned int len = (*ansp++) & 0x3f;
232-
233- if (!ADD_RDLEN(header, ansp, plen, len))
234- return 0;
235-
236- if (len == 0)
237- break; /* zero length label marks the end. */
238- }
239- }
240-
241- *namep = ansp;
242-
243- return 1;
244-}
245-
246-/* Go through RRs and check or fixup the domain names contained within */
247-static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
248-{
249- int i, type, class, rdlen;
250- unsigned char *pp;
251-
252- for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
253- {
254- pp = p;
255-
256- if (!(p = skip_name(p, header, plen, 10)))
257- return 0;
258-
259- GETSHORT(type, p);
260- GETSHORT(class, p);
261- p += 4; /* TTL */
262- GETSHORT(rdlen, p);
263-
264- if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
265- {
266- /* fixup name of RR */
267- if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
268- return 0;
269-
270- if (class == C_IN)
271- {
272- u16 *d;
273-
274- for (pp = p, d = get_desc(type); *d != (u16)-1; d++)
275- {
276- if (*d != 0)
277- pp += *d;
278- else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
279- return 0;
280- }
281- }
282- }
283-
284- if (!ADD_RDLEN(header, p, plen, rdlen))
285- return 0;
286- }
287-
288- return 1;
289-}
290-
291-
292-size_t filter_rrsigs(struct dns_header *header, size_t plen)
293-{
294- static unsigned char **rrs;
295- static int rr_sz = 0;
296-
297- unsigned char *p = (unsigned char *)(header+1);
298- int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
299-
300- if (ntohs(header->qdcount) != 1 ||
301- !(p = skip_name(p, header, plen, 4)))
302- return plen;
303-
304- GETSHORT(qtype, p);
305- GETSHORT(qclass, p);
306-
307- /* First pass, find pointers to start and end of all the records we wish to elide:
308- records added for DNSSEC, unless explicity queried for */
309- for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
310- i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
311- i++)
312- {
313- unsigned char *pstart = p;
314- int type, class;
315-
316- if (!(p = skip_name(p, header, plen, 10)))
317- return plen;
318-
319- GETSHORT(type, p);
320- GETSHORT(class, p);
321- p += 4; /* TTL */
322- GETSHORT(rdlen, p);
323-
324- if ((type == T_NSEC || type == T_NSEC3 || type == T_RRSIG) &&
325- (type != qtype || class != qclass))
326- {
327- if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
328- return plen;
329-
330- rrs[rr_found++] = pstart;
331-
332- if (!ADD_RDLEN(header, p, plen, rdlen))
333- return plen;
334-
335- rrs[rr_found++] = p;
336-
337- if (i < ntohs(header->ancount))
338- chop_an++;
339- else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
340- chop_ns++;
341- else
342- chop_ar++;
343- }
344- else if (!ADD_RDLEN(header, p, plen, rdlen))
345- return plen;
346- }
347-
348- /* Nothing to do. */
349- if (rr_found == 0)
350- return plen;
351-
352- /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
353- point to records we're going to elide. This is theoretically possible, but unlikely. If
354- it happens, we give up and leave the answer unchanged. */
355- p = (unsigned char *)(header+1);
356-
357- /* question first */
358- if (!check_name(&p, header, plen, 0, rrs, rr_found))
359- return plen;
360- p += 4; /* qclass, qtype */
361-
362- /* Now answers and NS */
363- if (!check_rrs(p, header, plen, 0, rrs, rr_found))
364- return plen;
365-
366- /* Third pass, elide records */
367- for (p = rrs[0], i = 1; i < rr_found; i += 2)
368- {
369- unsigned char *start = rrs[i];
370- unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
371-
372- memmove(p, start, end-start);
373- p += end-start;
374- }
375-
376- plen = p - (unsigned char *)header;
377- header->ancount = htons(ntohs(header->ancount) - chop_an);
378- header->nscount = htons(ntohs(header->nscount) - chop_ns);
379- header->arcount = htons(ntohs(header->arcount) - chop_ar);
380-
381- /* Fourth pass, fix up pointers in the remaining records */
382- p = (unsigned char *)(header+1);
383-
384- check_name(&p, header, plen, 1, rrs, rr_found);
385- p += 4; /* qclass, qtype */
386-
387- check_rrs(p, header, plen, 1, rrs, rr_found);
388-
389- return plen;
390-}
391-
392 unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
393 {
394 int q;
395diff --git a/src/forward.c b/src/forward.c
396index dd22a62..3e801c8 100644
397--- a/src/forward.c
398+++ b/src/forward.c
399@@ -662,7 +662,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
400
401 /* If the requestor didn't set the DO bit, don't return DNSSEC info. */
402 if (!do_bit)
403- n = filter_rrsigs(header, n);
404+ n = rrfilter(header, n, 1);
405 #endif
406
407 /* do this after extract_addresses. Ensure NODATA reply and remove
408diff --git a/src/rrfilter.c b/src/rrfilter.c
409new file mode 100644
410index 0000000..ae12261
411--- /dev/null
412+++ b/src/rrfilter.c
413@@ -0,0 +1,339 @@
414+/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
415+
416+ This program is free software; you can redistribute it and/or modify
417+ it under the terms of the GNU General Public License as published by
418+ the Free Software Foundation; version 2 dated June, 1991, or
419+ (at your option) version 3 dated 29 June, 2007.
420+
421+ This program is distributed in the hope that it will be useful,
422+ but WITHOUT ANY WARRANTY; without even the implied warranty of
423+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
424+ GNU General Public License for more details.
425+
426+ You should have received a copy of the GNU General Public License
427+ along with this program. If not, see <http://www.gnu.org/licenses/>.
428+*/
429+
430+/* Code to safely remove RRs from an DNS answer */
431+
432+#include "dnsmasq.h"
433+
434+/* Go through a domain name, find "pointers" and fix them up based on how many bytes
435+ we've chopped out of the packet, or check they don't point into an elided part. */
436+static int check_name(unsigned char **namep, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
437+{
438+ unsigned char *ansp = *namep;
439+
440+ while(1)
441+ {
442+ unsigned int label_type;
443+
444+ if (!CHECK_LEN(header, ansp, plen, 1))
445+ return 0;
446+
447+ label_type = (*ansp) & 0xc0;
448+
449+ if (label_type == 0xc0)
450+ {
451+ /* pointer for compression. */
452+ unsigned int offset;
453+ int i;
454+ unsigned char *p;
455+
456+ if (!CHECK_LEN(header, ansp, plen, 2))
457+ return 0;
458+
459+ offset = ((*ansp++) & 0x3f) << 8;
460+ offset |= *ansp++;
461+
462+ p = offset + (unsigned char *)header;
463+
464+ for (i = 0; i < rr_count; i++)
465+ if (p < rrs[i])
466+ break;
467+ else
468+ if (i & 1)
469+ offset -= rrs[i] - rrs[i-1];
470+
471+ /* does the pointer end up in an elided RR? */
472+ if (i & 1)
473+ return 0;
474+
475+ /* No, scale the pointer */
476+ if (fixup)
477+ {
478+ ansp -= 2;
479+ *ansp++ = (offset >> 8) | 0xc0;
480+ *ansp++ = offset & 0xff;
481+ }
482+ break;
483+ }
484+ else if (label_type == 0x80)
485+ return 0; /* reserved */
486+ else if (label_type == 0x40)
487+ {
488+ /* Extended label type */
489+ unsigned int count;
490+
491+ if (!CHECK_LEN(header, ansp, plen, 2))
492+ return 0;
493+
494+ if (((*ansp++) & 0x3f) != 1)
495+ return 0; /* we only understand bitstrings */
496+
497+ count = *(ansp++); /* Bits in bitstring */
498+
499+ if (count == 0) /* count == 0 means 256 bits */
500+ ansp += 32;
501+ else
502+ ansp += ((count-1)>>3)+1;
503+ }
504+ else
505+ { /* label type == 0 Bottom six bits is length */
506+ unsigned int len = (*ansp++) & 0x3f;
507+
508+ if (!ADD_RDLEN(header, ansp, plen, len))
509+ return 0;
510+
511+ if (len == 0)
512+ break; /* zero length label marks the end. */
513+ }
514+ }
515+
516+ *namep = ansp;
517+
518+ return 1;
519+}
520+
521+/* Go through RRs and check or fixup the domain names contained within */
522+static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, int fixup, unsigned char **rrs, int rr_count)
523+{
524+ int i, j, type, class, rdlen;
525+ unsigned char *pp;
526+
527+ for (i = 0; i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount); i++)
528+ {
529+ pp = p;
530+
531+ if (!(p = skip_name(p, header, plen, 10)))
532+ return 0;
533+
534+ GETSHORT(type, p);
535+ GETSHORT(class, p);
536+ p += 4; /* TTL */
537+ GETSHORT(rdlen, p);
538+
539+ /* If this RR is to be elided, don't fix up its contents */
540+ for (j = 0; j < rr_count; j += 2)
541+ if (rrs[j] == pp)
542+ break;
543+
544+ if (j >= rr_count)
545+ {
546+ /* fixup name of RR */
547+ if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
548+ return 0;
549+
550+ if (class == C_IN)
551+ {
552+ u16 *d;
553+
554+ for (pp = p, d = rrfilter_desc(type); *d != (u16)-1; d++)
555+ {
556+ if (*d != 0)
557+ pp += *d;
558+ else if (!check_name(&pp, header, plen, fixup, rrs, rr_count))
559+ return 0;
560+ }
561+ }
562+ }
563+
564+ if (!ADD_RDLEN(header, p, plen, rdlen))
565+ return 0;
566+ }
567+
568+ return 1;
569+}
570+
571+
572+/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
573+size_t rrfilter(struct dns_header *header, size_t plen, int mode)
574+{
575+ static unsigned char **rrs;
576+ static int rr_sz = 0;
577+
578+ unsigned char *p = (unsigned char *)(header+1);
579+ int i, rdlen, qtype, qclass, rr_found, chop_an, chop_ns, chop_ar;
580+
581+ if (ntohs(header->qdcount) != 1 ||
582+ !(p = skip_name(p, header, plen, 4)))
583+ return plen;
584+
585+ GETSHORT(qtype, p);
586+ GETSHORT(qclass, p);
587+
588+ /* First pass, find pointers to start and end of all the records we wish to elide:
589+ records added for DNSSEC, unless explicity queried for */
590+ for (rr_found = 0, chop_ns = 0, chop_an = 0, chop_ar = 0, i = 0;
591+ i < ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount);
592+ i++)
593+ {
594+ unsigned char *pstart = p;
595+ int type, class;
596+
597+ if (!(p = skip_name(p, header, plen, 10)))
598+ return plen;
599+
600+ GETSHORT(type, p);
601+ GETSHORT(class, p);
602+ p += 4; /* TTL */
603+ GETSHORT(rdlen, p);
604+
605+ if (!ADD_RDLEN(header, p, plen, rdlen))
606+ return plen;
607+
608+ /* Don't remove the answer. */
609+ if (i < ntohs(header->ancount) && type == qtype && class == qclass)
610+ continue;
611+
612+ if (mode == 0) /* EDNS */
613+ {
614+ /* EDNS mode, remove T_OPT from additional section only */
615+ if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
616+ continue;
617+ }
618+ else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
619+ /* DNSSEC mode, remove SIGs and NSECs from all three sections. */
620+ continue;
621+
622+
623+ if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
624+ return plen;
625+
626+ rrs[rr_found++] = pstart;
627+ rrs[rr_found++] = p;
628+
629+ if (i < ntohs(header->ancount))
630+ chop_an++;
631+ else if (i < (ntohs(header->nscount) + ntohs(header->ancount)))
632+ chop_ns++;
633+ else
634+ chop_ar++;
635+ }
636+
637+ /* Nothing to do. */
638+ if (rr_found == 0)
639+ return plen;
640+
641+ /* Second pass, look for pointers in names in the records we're keeping and make sure they don't
642+ point to records we're going to elide. This is theoretically possible, but unlikely. If
643+ it happens, we give up and leave the answer unchanged. */
644+ p = (unsigned char *)(header+1);
645+
646+ /* question first */
647+ if (!check_name(&p, header, plen, 0, rrs, rr_found))
648+ return plen;
649+ p += 4; /* qclass, qtype */
650+
651+ /* Now answers and NS */
652+ if (!check_rrs(p, header, plen, 0, rrs, rr_found))
653+ return plen;
654+
655+ /* Third pass, elide records */
656+ for (p = rrs[0], i = 1; i < rr_found; i += 2)
657+ {
658+ unsigned char *start = rrs[i];
659+ unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen;
660+
661+ memmove(p, start, end-start);
662+ p += end-start;
663+ }
664+
665+ plen = p - (unsigned char *)header;
666+ header->ancount = htons(ntohs(header->ancount) - chop_an);
667+ header->nscount = htons(ntohs(header->nscount) - chop_ns);
668+ header->arcount = htons(ntohs(header->arcount) - chop_ar);
669+
670+ /* Fourth pass, fix up pointers in the remaining records */
671+ p = (unsigned char *)(header+1);
672+
673+ check_name(&p, header, plen, 1, rrs, rr_found);
674+ p += 4; /* qclass, qtype */
675+
676+ check_rrs(p, header, plen, 1, rrs, rr_found);
677+
678+ return plen;
679+}
680+
681+/* This is used in the DNSSEC code too, hence it's exported */
682+u16 *rrfilter_desc(int type)
683+{
684+ /* List of RRtypes which include domains in the data.
685+ 0 -> domain
686+ integer -> no of plain bytes
687+ -1 -> end
688+
689+ zero is not a valid RRtype, so the final entry is returned for
690+ anything which needs no mangling.
691+ */
692+
693+ static u16 rr_desc[] =
694+ {
695+ T_NS, 0, -1,
696+ T_MD, 0, -1,
697+ T_MF, 0, -1,
698+ T_CNAME, 0, -1,
699+ T_SOA, 0, 0, -1,
700+ T_MB, 0, -1,
701+ T_MG, 0, -1,
702+ T_MR, 0, -1,
703+ T_PTR, 0, -1,
704+ T_MINFO, 0, 0, -1,
705+ T_MX, 2, 0, -1,
706+ T_RP, 0, 0, -1,
707+ T_AFSDB, 2, 0, -1,
708+ T_RT, 2, 0, -1,
709+ T_SIG, 18, 0, -1,
710+ T_PX, 2, 0, 0, -1,
711+ T_NXT, 0, -1,
712+ T_KX, 2, 0, -1,
713+ T_SRV, 6, 0, -1,
714+ T_DNAME, 0, -1,
715+ 0, -1 /* wildcard/catchall */
716+ };
717+
718+ u16 *p = rr_desc;
719+
720+ while (*p != type && *p != 0)
721+ while (*p++ != (u16)-1);
722+
723+ return p+1;
724+}
725+
726+int expand_workspace(unsigned char ***wkspc, int *szp, int new)
727+{
728+ unsigned char **p;
729+ int old = *szp;
730+
731+ if (old >= new+1)
732+ return 1;
733+
734+ if (new >= 100)
735+ return 0;
736+
737+ new += 5;
738+
739+ if (!(p = whine_malloc(new * sizeof(unsigned char **))))
740+ return 0;
741+
742+ if (old != 0 && *wkspc)
743+ {
744+ memcpy(p, *wkspc, old * sizeof(unsigned char **));
745+ free(*wkspc);
746+ }
747+
748+ *wkspc = p;
749+ *szp = new;
750+
751+ return 1;
752+}
753--
7541.7.10.4
755