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