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