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