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 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 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 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