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