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 #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 
82 ssize_t
ns_rdata_unpack(const u_char * msg,const u_char * eom,ns_type type,const u_char * rdata,size_t rdlen,u_char * nrdata,size_t nrdsiz)83 ns_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 
174 int
ns_rdata_equal(ns_type type,const u_char * rdata1,size_t rdlen1,const u_char * rdata2,size_t rdlen2)175 ns_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 
247 int
ns_rdata_refers(ns_type type,const u_char * rdata,size_t rdlen,const u_char * nname)248 ns_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