1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * University Copyright- Copyright (c) 1982, 1986, 1988 33 * The Regents of the University of California 34 * All Rights Reserved 35 * 36 * University Acknowledgment- Portions of this document are derived from 37 * software developed by the University of California, Berkeley, and its 38 * contributors. 39 */ 40 41 #pragma ident "%Z%%M% %I% %E% SMI" 42 43 #include "c_synonyms.h" 44 #include <stdio.h> 45 #include <sys/types.h> 46 #include <sys/socket.h> 47 #include <sys/stat.h> 48 #include <netinet/in.h> 49 #include <arpa/nameser.h> 50 #include <resolv.h> 51 #include <errno.h> 52 #include <netdb.h> 53 54 /* 55 * Kludge to time out quickly if there is no /etc/resolv.conf 56 * and a TCP connection to the local DNS server fails. 57 * 58 * Moved function from res_send.c to res_mkquery.c. This 59 * solves a long timeout problem with nslookup. 60 * 61 * __areweinnamed is needed because there is a possibility that the 62 * user might do bad things to resolv.conf and cause in.named to call 63 * _confcheck and deadlock the server. 64 */ 65 66 int __areweinnamed() 67 { 68 return (0); 69 } 70 71 static int _confcheck() 72 { 73 int ns; 74 struct stat rc_stat; 75 struct sockaddr_in ns_sin; 76 77 78 /* First, we check to see if /etc/resolv.conf exists. 79 * If it doesn't, then localhost is mostlikely to be 80 * the nameserver. 81 */ 82 if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) { 83 84 /* Next, we check to see if _res.nsaddr is set to loopback. 85 * If it isn't, it has been altered by the application 86 * explicitly and we then want to bail with success. 87 */ 88 if (__areweinnamed()) 89 return (0); 90 91 if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) { 92 93 /* Lastly, we try to connect to the TCP port of the 94 * nameserver. If this fails, then we know that 95 * DNS is misconfigured and we can quickly exit. 96 */ 97 ns = socket(AF_INET, SOCK_STREAM, 0); 98 IN_SET_LOOPBACK_ADDR(&ns_sin); 99 ns_sin.sin_port = htons(NAMESERVER_PORT); 100 if (connect(ns, (struct sockaddr *) &ns_sin, 101 sizeof ns_sin) == -1) { 102 close(ns); 103 return(-1); 104 } 105 else { 106 close(ns); 107 return(0); 108 } 109 } 110 111 return(0); 112 } 113 114 return (0); 115 } 116 117 /* 118 * Form all types of queries. 119 * Returns the size of the result or -1. 120 */ 121 int 122 res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen) 123 int op; /* opcode of query */ 124 char *dname; /* domain name */ 125 int class, type; /* class and type of query */ 126 char *data; /* resource record data */ 127 int datalen; /* length of data */ 128 struct rrec *newrr; /* new rr for modify or append */ 129 char *buf; /* buffer to put query */ 130 int buflen; /* size of buffer */ 131 { 132 register HEADER *hp; 133 register char *cp; 134 register int n; 135 char *dnptrs[10], **dpp, **lastdnptr; 136 137 #ifdef DEBUG 138 if (_res.options & RES_DEBUG) 139 printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type); 140 #endif /* DEBUG */ 141 142 /* 143 * Check to see if we can bailout quickly. 144 * Also rerun res_init if we failed in the past. 145 */ 146 147 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 148 h_errno = NO_RECOVERY; 149 return(-1); 150 } 151 152 if (_confcheck() == -1) { 153 _res.options &= ~RES_INIT; 154 h_errno = NO_RECOVERY; 155 return(-1); 156 } 157 158 /* 159 * Initialize header fields. 160 */ 161 if ((buf == NULL) || (buflen < sizeof (HEADER))) 162 return (-1); 163 #ifdef SYSV 164 memset(buf, 0, sizeof (HEADER)); 165 #else 166 bzero(buf, sizeof (HEADER)); 167 #endif 168 hp = (HEADER *) buf; 169 hp->id = htons(++_res.id); 170 hp->opcode = op; 171 hp->pr = (_res.options & RES_PRIMARY) != 0; 172 hp->rd = (_res.options & RES_RECURSE) != 0; 173 hp->rcode = NOERROR; 174 cp = buf + sizeof (HEADER); 175 buflen -= sizeof (HEADER); 176 dpp = dnptrs; 177 *dpp++ = buf; 178 *dpp++ = NULL; 179 lastdnptr = dnptrs + sizeof (dnptrs) / sizeof (dnptrs[0]); 180 /* 181 * perform opcode specific processing 182 */ 183 switch (op) { 184 case QUERY: 185 if ((buflen -= QFIXEDSZ) < 0) 186 return (-1); 187 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 188 return (-1); 189 cp += n; 190 buflen -= n; 191 putshort(type, cp); 192 cp += sizeof (u_short); 193 putshort(class, cp); 194 cp += sizeof (u_short); 195 hp->qdcount = htons(1); 196 if (op == QUERY || data == NULL) 197 break; 198 /* 199 * Make an additional record for completion domain. 200 */ 201 buflen -= RRFIXEDSZ; 202 if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0) 203 return (-1); 204 cp += n; 205 buflen -= n; 206 putshort(T_NULL, cp); 207 cp += sizeof (u_short); 208 putshort(class, cp); 209 cp += sizeof (u_short); 210 putlong(0, cp); 211 cp += sizeof (u_long); 212 putshort(0, cp); 213 cp += sizeof (u_short); 214 hp->arcount = htons(1); 215 break; 216 217 case IQUERY: 218 /* 219 * Initialize answer section 220 */ 221 if (buflen < 1 + RRFIXEDSZ + datalen) 222 return (-1); 223 *cp++ = '\0'; /* no domain name */ 224 putshort(type, cp); 225 cp += sizeof (u_short); 226 putshort(class, cp); 227 cp += sizeof (u_short); 228 putlong(0, cp); 229 cp += sizeof (u_long); 230 putshort(datalen, cp); 231 cp += sizeof (u_short); 232 if (datalen) { 233 #ifdef SYSV 234 memcpy((void *)cp, (void *)data, datalen); 235 #else 236 bcopy(data, cp, datalen); 237 #endif 238 cp += datalen; 239 } 240 hp->ancount = htons(1); 241 break; 242 243 #ifdef ALLOW_UPDATES 244 /* 245 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA 246 * (Record to be modified is followed by its replacement in msg.) 247 */ 248 case UPDATEM: 249 case UPDATEMA: 250 251 case UPDATED: 252 /* 253 * The res code for UPDATED and UPDATEDA is the same; user 254 * calls them differently: specifies data for UPDATED; server 255 * ignores data if specified for UPDATEDA. 256 */ 257 case UPDATEDA: 258 buflen -= RRFIXEDSZ + datalen; 259 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 260 return (-1); 261 cp += n; 262 putshort(type, cp); 263 cp += sizeof (u_short); 264 putshort(class, cp); 265 cp += sizeof (u_short); 266 putlong(0, cp); 267 cp += sizeof (u_long); 268 putshort(datalen, cp); 269 cp += sizeof (u_short); 270 if (datalen) { 271 #ifdef SYSV 272 memcpy((void *)cp, (void *)data, datalen); 273 #else 274 bcopy(data, cp, datalen); 275 #endif 276 cp += datalen; 277 } 278 if ((op == UPDATED) || (op == UPDATEDA)) { 279 hp->ancount = htons(0); 280 break; 281 } 282 /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ 283 284 case UPDATEA: /* Add new resource record */ 285 buflen -= RRFIXEDSZ + datalen; 286 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 287 return (-1); 288 cp += n; 289 putshort(newrr->r_type, cp); 290 cp += sizeof (u_short); 291 putshort(newrr->r_class, cp); 292 cp += sizeof (u_short); 293 putlong(0, cp); 294 cp += sizeof (u_long); 295 putshort(newrr->r_size, cp); 296 cp += sizeof (u_short); 297 if (newrr->r_size) { 298 #ifdef SYSV 299 memcpy((void *)cp, newrr->r_data, newrr->r_size); 300 #else 301 bcopy(newrr->r_data, cp, newrr->r_size); 302 #endif 303 cp += newrr->r_size; 304 } 305 hp->ancount = htons(0); 306 break; 307 308 #endif /* ALLOW_UPDATES */ 309 } 310 return (cp - buf); 311 } 312