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 * Copyright 1998 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 "synonyms.h" 43 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 res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen) 122 int op; /* opcode of query */ 123 char *dname; /* domain name */ 124 int class, type; /* class and type of query */ 125 char *data; /* resource record data */ 126 int datalen; /* length of data */ 127 struct rrec *newrr; /* new rr for modify or append */ 128 char *buf; /* buffer to put query */ 129 int buflen; /* size of buffer */ 130 { 131 register HEADER *hp; 132 register char *cp; 133 register int n; 134 char *dnptrs[10], **dpp, **lastdnptr; 135 136 #ifdef DEBUG 137 if (_res.options & RES_DEBUG) 138 printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type); 139 #endif DEBUG 140 141 /* 142 * Check to see if we can bailout quickly. 143 * Also rerun res_init if we failed in the past. 144 */ 145 146 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 147 h_errno = NO_RECOVERY; 148 return(-1); 149 } 150 151 if (_confcheck() == -1) { 152 _res.options &= ~RES_INIT; 153 h_errno = NO_RECOVERY; 154 return(-1); 155 } 156 157 /* 158 * Initialize header fields. 159 */ 160 if ((buf == NULL) || (buflen < sizeof (HEADER))) 161 return (-1); 162 #ifdef SYSV 163 memset(buf, 0, sizeof (HEADER)); 164 #else 165 bzero(buf, sizeof (HEADER)); 166 #endif 167 hp = (HEADER *) buf; 168 hp->id = htons(++_res.id); 169 hp->opcode = op; 170 hp->pr = (_res.options & RES_PRIMARY) != 0; 171 hp->rd = (_res.options & RES_RECURSE) != 0; 172 hp->rcode = NOERROR; 173 cp = buf + sizeof (HEADER); 174 buflen -= sizeof (HEADER); 175 dpp = dnptrs; 176 *dpp++ = buf; 177 *dpp++ = NULL; 178 lastdnptr = dnptrs + sizeof (dnptrs) / sizeof (dnptrs[0]); 179 /* 180 * perform opcode specific processing 181 */ 182 switch (op) { 183 case QUERY: 184 if ((buflen -= QFIXEDSZ) < 0) 185 return (-1); 186 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 187 return (-1); 188 cp += n; 189 buflen -= n; 190 putshort(type, cp); 191 cp += sizeof (u_short); 192 putshort(class, cp); 193 cp += sizeof (u_short); 194 hp->qdcount = htons(1); 195 if (op == QUERY || data == NULL) 196 break; 197 /* 198 * Make an additional record for completion domain. 199 */ 200 buflen -= RRFIXEDSZ; 201 if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0) 202 return (-1); 203 cp += n; 204 buflen -= n; 205 putshort(T_NULL, cp); 206 cp += sizeof (u_short); 207 putshort(class, cp); 208 cp += sizeof (u_short); 209 putlong(0, cp); 210 cp += sizeof (u_long); 211 putshort(0, cp); 212 cp += sizeof (u_short); 213 hp->arcount = htons(1); 214 break; 215 216 case IQUERY: 217 /* 218 * Initialize answer section 219 */ 220 if (buflen < 1 + RRFIXEDSZ + datalen) 221 return (-1); 222 *cp++ = '\0'; /* no domain name */ 223 putshort(type, cp); 224 cp += sizeof (u_short); 225 putshort(class, cp); 226 cp += sizeof (u_short); 227 putlong(0, cp); 228 cp += sizeof (u_long); 229 putshort(datalen, cp); 230 cp += sizeof (u_short); 231 if (datalen) { 232 #ifdef SYSV 233 memcpy((void *)cp, (void *)data, datalen); 234 #else 235 bcopy(data, cp, datalen); 236 #endif 237 cp += datalen; 238 } 239 hp->ancount = htons(1); 240 break; 241 242 #ifdef ALLOW_UPDATES 243 /* 244 * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA 245 * (Record to be modified is followed by its replacement in msg.) 246 */ 247 case UPDATEM: 248 case UPDATEMA: 249 250 case UPDATED: 251 /* 252 * The res code for UPDATED and UPDATEDA is the same; user 253 * calls them differently: specifies data for UPDATED; server 254 * ignores data if specified for UPDATEDA. 255 */ 256 case UPDATEDA: 257 buflen -= RRFIXEDSZ + datalen; 258 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 259 return (-1); 260 cp += n; 261 putshort(type, cp); 262 cp += sizeof (u_short); 263 putshort(class, cp); 264 cp += sizeof (u_short); 265 putlong(0, cp); 266 cp += sizeof (u_long); 267 putshort(datalen, cp); 268 cp += sizeof (u_short); 269 if (datalen) { 270 #ifdef SYSV 271 memcpy((void *)cp, (void *)data, datalen); 272 #else 273 bcopy(data, cp, datalen); 274 #endif 275 cp += datalen; 276 } 277 if ((op == UPDATED) || (op == UPDATEDA)) { 278 hp->ancount = htons(0); 279 break; 280 } 281 /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ 282 283 case UPDATEA: /* Add new resource record */ 284 buflen -= RRFIXEDSZ + datalen; 285 if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) 286 return (-1); 287 cp += n; 288 putshort(newrr->r_type, cp); 289 cp += sizeof (u_short); 290 putshort(newrr->r_class, cp); 291 cp += sizeof (u_short); 292 putlong(0, cp); 293 cp += sizeof (u_long); 294 putshort(newrr->r_size, cp); 295 cp += sizeof (u_short); 296 if (newrr->r_size) { 297 #ifdef SYSV 298 memcpy((void *)cp, newrr->r_data, newrr->r_size); 299 #else 300 bcopy(newrr->r_data, cp, newrr->r_size); 301 #endif 302 cp += newrr->r_size; 303 } 304 hp->ancount = htons(0); 305 break; 306 307 #endif ALLOW_UPDATES 308 } 309 return (cp - buf); 310 } 311