1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC") 9 * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003 Internet Software Consortium. 10 * 11 * Permission to use, copy, modify, and/or distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 16 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 18 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 19 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 20 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24 /* 25 * Copyright (c) 1985, 1993 26 * The Regents of the University of California. All rights reserved. 27 * 28 * Redistribution and use in source and binary forms, with or without 29 * modification, are permitted provided that the following conditions 30 * are met: 31 * 1. Redistributions of source code must retain the above copyright 32 * notice, this list of conditions and the following disclaimer. 33 * 2. Redistributions in binary form must reproduce the above copyright 34 * notice, this list of conditions and the following disclaimer in the 35 * documentation and/or other materials provided with the distribution. 36 * 3. All advertising materials mentioning features or use of this software 37 * must display the following acknowledgement: 38 * This product includes software developed by the University of 39 * California, Berkeley and its contributors. 40 * 4. Neither the name of the University nor the names of its contributors 41 * may be used to endorse or promote products derived from this software 42 * without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57 /* 58 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 59 * 60 * Permission to use, copy, modify, and distribute this software for any 61 * purpose with or without fee is hereby granted, provided that the above 62 * copyright notice and this permission notice appear in all copies, and that 63 * the name of Digital Equipment Corporation not be used in advertising or 64 * publicity pertaining to distribution of the document or software without 65 * specific, written prior permission. 66 * 67 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 68 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 69 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 70 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 71 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 72 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 73 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 74 * SOFTWARE. 75 */ 76 77 #include "port_before.h" 78 #include <sys/types.h> 79 #include <sys/param.h> 80 #include <netinet/in.h> 81 #include <arpa/nameser.h> 82 83 #ifdef SUNW_CONFCHECK 84 #include <sys/socket.h> 85 #include <errno.h> 86 #include <sys/stat.h> 87 #endif /* SUNW_CONFCHECK */ 88 89 90 #include <netdb.h> 91 #include <resolv.h> 92 #include <stdio.h> 93 #include <string.h> 94 #include "port_after.h" 95 96 /* Options. Leave them on. */ 97 #define DEBUG 98 99 extern const char *_res_opcodes[]; 100 101 #ifdef SUNW_CONFCHECK 102 static int _confcheck(res_state statp); 103 #endif /* SUNW_CONFCHECK */ 104 105 106 /*% 107 * Form all types of queries. 108 * Returns the size of the result or -1. 109 */ 110 int 111 res_nmkquery(res_state statp, 112 int op, /*!< opcode of query */ 113 const char *dname, /*!< domain name */ 114 int class, int type, /*!< class and type of query */ 115 const u_char *data, /*!< resource record data */ 116 int datalen, /*!< length of data */ 117 const u_char *newrr_in, /*!< new rr for modify or append */ 118 u_char *buf, /*!< buffer to put query */ 119 int buflen) /*!< size of buffer */ 120 { 121 register HEADER *hp; 122 register u_char *cp, *ep; 123 register int n; 124 u_char *dnptrs[20], **dpp, **lastdnptr; 125 126 UNUSED(newrr_in); 127 128 #ifdef DEBUG 129 if (statp->options & RES_DEBUG) 130 printf(";; res_nmkquery(%s, %s, %s, %s)\n", 131 _res_opcodes[op], dname, p_class(class), p_type(type)); 132 #endif 133 134 #ifdef SUNW_CONFCHECK 135 /* 136 * 1247019, 1265838, and 4034368: Check to see if we can 137 * bailout quickly. 138 */ 139 if (_confcheck(statp) == -1) { 140 RES_SET_H_ERRNO(statp, NO_RECOVERY); 141 return(-1); 142 } 143 #endif /* SUNW_CONFCHECK */ 144 145 /* 146 * Initialize header fields. 147 */ 148 if ((buf == NULL) || (buflen < HFIXEDSZ)) 149 return (-1); 150 memset(buf, 0, HFIXEDSZ); 151 hp = (HEADER *) buf; 152 statp->id = res_nrandomid(statp); 153 hp->id = htons(statp->id); 154 hp->opcode = op; 155 hp->rd = (statp->options & RES_RECURSE) != 0U; 156 hp->rcode = NOERROR; 157 cp = buf + HFIXEDSZ; 158 ep = buf + buflen; 159 dpp = dnptrs; 160 *dpp++ = buf; 161 *dpp++ = NULL; 162 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; 163 /* 164 * perform opcode specific processing 165 */ 166 switch (op) { 167 case QUERY: /*FALLTHROUGH*/ 168 case NS_NOTIFY_OP: 169 if (ep - cp < QFIXEDSZ) 170 return (-1); 171 if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, 172 lastdnptr)) < 0) 173 return (-1); 174 cp += n; 175 ns_put16(type, cp); 176 cp += INT16SZ; 177 ns_put16(class, cp); 178 cp += INT16SZ; 179 hp->qdcount = htons(1); 180 if (op == QUERY || data == NULL) 181 break; 182 /* 183 * Make an additional record for completion domain. 184 */ 185 if ((ep - cp) < RRFIXEDSZ) 186 return (-1); 187 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ, 188 dnptrs, lastdnptr); 189 if (n < 0) 190 return (-1); 191 cp += n; 192 ns_put16(T_NULL, cp); 193 cp += INT16SZ; 194 ns_put16(class, cp); 195 cp += INT16SZ; 196 ns_put32(0, cp); 197 cp += INT32SZ; 198 ns_put16(0, cp); 199 cp += INT16SZ; 200 hp->arcount = htons(1); 201 break; 202 203 case IQUERY: 204 /* 205 * Initialize answer section 206 */ 207 if (ep - cp < 1 + RRFIXEDSZ + datalen) 208 return (-1); 209 *cp++ = '\0'; /*%< no domain name */ 210 ns_put16(type, cp); 211 cp += INT16SZ; 212 ns_put16(class, cp); 213 cp += INT16SZ; 214 ns_put32(0, cp); 215 cp += INT32SZ; 216 ns_put16(datalen, cp); 217 cp += INT16SZ; 218 if (datalen) { 219 memcpy(cp, data, datalen); 220 cp += datalen; 221 } 222 hp->ancount = htons(1); 223 break; 224 225 default: 226 return (-1); 227 } 228 return (cp - buf); 229 } 230 231 #ifdef RES_USE_EDNS0 232 /* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */ 233 234 int 235 res_nopt(res_state statp, 236 int n0, /*%< current offset in buffer */ 237 u_char *buf, /*%< buffer to put query */ 238 int buflen, /*%< size of buffer */ 239 int anslen) /*%< UDP answer buffer size */ 240 { 241 register HEADER *hp; 242 register u_char *cp, *ep; 243 u_int16_t flags = 0; 244 245 #ifdef DEBUG 246 if ((statp->options & RES_DEBUG) != 0U) 247 printf(";; res_nopt()\n"); 248 #endif 249 250 hp = (HEADER *) buf; 251 cp = buf + n0; 252 ep = buf + buflen; 253 254 if ((ep - cp) < 1 + RRFIXEDSZ) 255 return (-1); 256 257 *cp++ = 0; /*%< "." */ 258 ns_put16(ns_t_opt, cp); /*%< TYPE */ 259 cp += INT16SZ; 260 ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */ 261 cp += INT16SZ; 262 *cp++ = NOERROR; /*%< extended RCODE */ 263 *cp++ = 0; /*%< EDNS version */ 264 265 if (statp->options & RES_USE_DNSSEC) { 266 #ifdef DEBUG 267 if (statp->options & RES_DEBUG) 268 printf(";; res_opt()... ENDS0 DNSSEC\n"); 269 #endif 270 flags |= NS_OPT_DNSSEC_OK; 271 } 272 ns_put16(flags, cp); 273 cp += INT16SZ; 274 275 ns_put16(0U, cp); /*%< RDLEN */ 276 cp += INT16SZ; 277 278 hp->arcount = htons(ntohs(hp->arcount) + 1); 279 280 return (cp - buf); 281 } 282 283 /* 284 * Construct variable data (RDATA) block for OPT psuedo-RR, append it 285 * to the buffer, then update the RDLEN field (previously set to zero by 286 * res_nopt()) with the new RDATA length. 287 */ 288 int 289 res_nopt_rdata(res_state statp, 290 int n0, /*%< current offset in buffer */ 291 u_char *buf, /*%< buffer to put query */ 292 int buflen, /*%< size of buffer */ 293 u_char *rdata, /*%< ptr to start of opt rdata */ 294 u_short code, /*%< OPTION-CODE */ 295 u_short len, /*%< OPTION-LENGTH */ 296 u_char *data) /*%< OPTION_DATA */ 297 { 298 register u_char *cp, *ep; 299 300 #ifdef DEBUG 301 if ((statp->options & RES_DEBUG) != 0U) 302 printf(";; res_nopt_rdata()\n"); 303 #endif 304 305 cp = buf + n0; 306 ep = buf + buflen; 307 308 if ((ep - cp) < (4 + len)) 309 return (-1); 310 311 if (rdata < (buf + 2) || rdata >= ep) 312 return (-1); 313 314 ns_put16(code, cp); 315 cp += INT16SZ; 316 317 ns_put16(len, cp); 318 cp += INT16SZ; 319 320 memcpy(cp, data, len); 321 cp += len; 322 323 len = cp - rdata; 324 ns_put16(len, rdata - 2); /* Update RDLEN field */ 325 326 return (cp - buf); 327 } 328 #endif 329 330 #ifdef SUNW_CONFCHECK 331 332 /* 333 * Time out quickly if there is no /etc/resolv.conf and a TCP connection 334 * to the local DNS server fails. 335 */ 336 static int _confcheck(res_state statp) 337 { 338 int ns; 339 struct stat rc_stat; 340 struct sockaddr_in ns_sin; 341 342 /* First, we check to see if /etc/resolv.conf exists. 343 * If it doesn't, then it is likely that the localhost is 344 * the nameserver. 345 */ 346 if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) { 347 348 /* Next, we check to see if _res.nsaddr is set to loopback. 349 * If it isn't, it has been altered by the application 350 * explicitly and we then want to bail with success. 351 */ 352 if (statp->nsaddr.sin_addr.S_un.S_addr == 353 htonl(INADDR_LOOPBACK)) { 354 355 /* Lastly, we try to connect to the TCP port of the 356 * nameserver. If this fails, then we know that 357 * DNS is misconfigured and we can quickly exit. 358 */ 359 ns = socket(AF_INET, SOCK_STREAM, 0); 360 IN_SET_LOOPBACK_ADDR(&ns_sin); 361 ns_sin.sin_port = htons(NAMESERVER_PORT); 362 if (connect(ns, (struct sockaddr *) &ns_sin, 363 sizeof ns_sin) == -1) { 364 close(ns); 365 return(-1); 366 } 367 else { 368 close(ns); 369 370 return(0); 371 } 372 } 373 374 return(0); 375 } 376 377 return (0); 378 } 379 #endif /* SUNW_CONFCHECK */ 380 381 /*! \file */ 382