1 /*        $NetBSD: ns_rdata.c,v 1.1.1.2 2012/09/09 16:08:03 christos Exp $      */
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
20 static 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 
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