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