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
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)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
ns_rdata_equal(ns_type type,const u_char * rdata1,size_t rdlen1,const u_char * rdata2,size_t rdlen2)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
ns_rdata_refers(ns_type type,const u_char * rdata,size_t rdlen,const u_char * nname)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