1/*	$NetBSD$	*/
2
3/*
4 * Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#ifndef lint
20static const char rcsid[] = "Id: ns_rdata.c,v 1.2 2009/01/23 23:49:15 tbox Exp";
21#endif
22
23#include "port_before.h"
24
25#if __OpenBSD__
26#include <sys/types.h>
27#endif
28#include <netinet/in.h>
29#include <arpa/nameser.h>
30
31#include <errno.h>
32#include <resolv.h>
33#include <string.h>
34
35#include "port_after.h"
36
37#define CONSUME_SRC \
38	do { \
39		rdata += n, rdlen -= n; \
40	} while (0)
41
42#define CONSUME_DST \
43	do { \
44		nrdata += n, nrdsiz -= n, nrdlen += n; \
45	} while (0)
46
47#define UNPACK_DNAME \
48	do { \
49		size_t t; \
50		\
51		if ((n = ns_name_unpack2(msg,eom,rdata,nrdata,nrdsiz,&t))<0) {\
52			errno = EMSGSIZE; \
53			return (-1); \
54		} \
55		CONSUME_SRC; \
56		n = t; \
57		CONSUME_DST; \
58	} while (0)
59
60#define UNPACK_SOME(x) \
61	do { \
62		n = (x); \
63		if ((size_t)n > rdlen || (size_t)n > nrdsiz) { \
64			errno = EMSGSIZE; \
65			return (-1); \
66		} \
67		memcpy(nrdata, rdata, n); \
68		CONSUME_SRC; CONSUME_DST; \
69	} while (0)
70
71#define	UNPACK_REST(x) \
72	do { \
73		n = (x); \
74		if ((size_t)n != rdlen) { \
75			errno = EMSGSIZE; \
76			return (-1); \
77		} \
78		memcpy(nrdata, rdata, n); \
79		CONSUME_SRC; CONSUME_DST; \
80	} while (0)
81
82ssize_t
83ns_rdata_unpack(const u_char *msg, const u_char *eom,
84		ns_type type, const u_char *rdata, size_t rdlen,
85		u_char *nrdata, size_t nrdsiz)
86{
87	size_t nrdlen = 0;
88	int n;
89
90	switch (type) {
91	case ns_t_a:
92		UNPACK_REST(NS_INADDRSZ);
93		break;
94	case ns_t_aaaa:
95		UNPACK_REST(NS_IN6ADDRSZ);
96		break;
97	case ns_t_cname:
98	case ns_t_mb:
99	case ns_t_mg:
100	case ns_t_mr:
101	case ns_t_ns:
102	case ns_t_ptr:
103	case ns_t_dname:
104		UNPACK_DNAME;
105		break;
106	case ns_t_soa:
107		UNPACK_DNAME;
108		UNPACK_DNAME;
109		UNPACK_SOME(NS_INT32SZ * 5);
110		break;
111	case ns_t_mx:
112	case ns_t_afsdb:
113	case ns_t_rt:
114		UNPACK_SOME(NS_INT16SZ);
115		UNPACK_DNAME;
116		break;
117	case ns_t_px:
118		UNPACK_SOME(NS_INT16SZ);
119		UNPACK_DNAME;
120		UNPACK_DNAME;
121		break;
122	case ns_t_srv:
123		UNPACK_SOME(NS_INT16SZ * 3);
124		UNPACK_DNAME;
125		break;
126	case ns_t_minfo:
127	case ns_t_rp:
128		UNPACK_DNAME;
129		UNPACK_DNAME;
130		break;
131	default:
132		UNPACK_SOME(rdlen);
133		break;
134	}
135	if (rdlen > 0) {
136		errno = EMSGSIZE;
137		return (-1);
138	}
139	return (nrdlen);
140}
141
142#define	EQUAL_CONSUME \
143	do { \
144		rdata1 += n, rdlen1 -= n; \
145		rdata2 += n, rdlen2 -= n; \
146	} while (0)
147
148#define	EQUAL_DNAME \
149	do { \
150		ssize_t n; \
151		\
152		if (rdlen1 != rdlen2) \
153			return (0); \
154		n = ns_name_eq(rdata1, rdlen1, rdata2, rdlen2); \
155		if (n <= 0) \
156			return (n); \
157		n = rdlen1; \
158		EQUAL_CONSUME; \
159	} while (0)
160
161#define	EQUAL_SOME(x) \
162	do { \
163		size_t n = (x); \
164		\
165		if (n > rdlen1 || n > rdlen2) { \
166			errno = EMSGSIZE; \
167			return (-1); \
168		} \
169		if (memcmp(rdata1, rdata2, n) != 0) \
170			return (0); \
171		EQUAL_CONSUME; \
172	} while (0)
173
174int
175ns_rdata_equal(ns_type type,
176	       const u_char *rdata1, size_t rdlen1,
177	       const u_char *rdata2, size_t rdlen2)
178{
179	switch (type) {
180	case ns_t_cname:
181	case ns_t_mb:
182	case ns_t_mg:
183	case ns_t_mr:
184	case ns_t_ns:
185	case ns_t_ptr:
186	case ns_t_dname:
187		EQUAL_DNAME;
188		break;
189	case ns_t_soa:
190		/* "There can be only one." --Highlander */
191		break;
192	case ns_t_mx:
193	case ns_t_afsdb:
194	case ns_t_rt:
195		EQUAL_SOME(NS_INT16SZ);
196		EQUAL_DNAME;
197		break;
198	case ns_t_px:
199		EQUAL_SOME(NS_INT16SZ);
200		EQUAL_DNAME;
201		EQUAL_DNAME;
202		break;
203	case ns_t_srv:
204		EQUAL_SOME(NS_INT16SZ * 3);
205		EQUAL_DNAME;
206		break;
207	case ns_t_minfo:
208	case ns_t_rp:
209		EQUAL_DNAME;
210		EQUAL_DNAME;
211		break;
212	default:
213		EQUAL_SOME(rdlen1);
214		break;
215	}
216	if (rdlen1 != 0 || rdlen2 != 0)
217		return (0);
218	return (1);
219}
220
221#define REFERS_DNAME \
222	do { \
223		int n; \
224		\
225		n = ns_name_eq(rdata, rdlen, nname, NS_MAXNNAME); \
226		if (n < 0) \
227			return (-1); \
228		if (n > 0) \
229			return (1); \
230		n = dn_skipname(rdata, rdata + rdlen); \
231		if (n < 0) \
232			return (-1); \
233		CONSUME_SRC; \
234	} while (0)
235
236#define	REFERS_SOME(x) \
237	do { \
238		size_t n = (x); \
239		\
240		if (n > rdlen) { \
241			errno = EMSGSIZE; \
242			return (-1); \
243		} \
244		CONSUME_SRC; \
245	} while (0)
246
247int
248ns_rdata_refers(ns_type type,
249		const u_char *rdata, size_t rdlen,
250		const u_char *nname)
251{
252	switch (type) {
253	case ns_t_cname:
254	case ns_t_mb:
255	case ns_t_mg:
256	case ns_t_mr:
257	case ns_t_ns:
258	case ns_t_ptr:
259	case ns_t_dname:
260		REFERS_DNAME;
261		break;
262	case ns_t_soa:
263		REFERS_DNAME;
264		REFERS_DNAME;
265		REFERS_SOME(NS_INT32SZ * 5);
266		break;
267	case ns_t_mx:
268	case ns_t_afsdb:
269	case ns_t_rt:
270		REFERS_SOME(NS_INT16SZ);
271		REFERS_DNAME;
272		break;
273	case ns_t_px:
274		REFERS_SOME(NS_INT16SZ);
275		REFERS_DNAME;
276		REFERS_DNAME;
277		break;
278	case ns_t_srv:
279		REFERS_SOME(NS_INT16SZ * 3);
280		REFERS_DNAME;
281		break;
282	case ns_t_minfo:
283	case ns_t_rp:
284		REFERS_DNAME;
285		REFERS_DNAME;
286		break;
287	default:
288		REFERS_SOME(rdlen);
289		break;
290	}
291	if (rdlen != 0) {
292		errno = EMSGSIZE;
293		return (-1);
294	}
295	return (0);
296}
297