1 /* 2 * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 * 9 */ 10 11 /* 12 * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan 13 * (Royal Institute of Technology, Stockholm, Sweden). 14 * All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 27 * 3. Neither the name of the Institute nor the names of its contributors 28 * may be used to endorse or promote products derived from this software 29 * without specific prior written permission. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 35 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41 * SUCH DAMAGE. 42 */ 43 44 #include <sendmail.h> 45 #if DNSMAP 46 # if NAMED_BIND 47 # include "sm_resolve.h" 48 49 SM_RCSID("$Id: sm_resolve.c,v 8.24.4.6 2002/06/25 04:22:41 ca Exp $") 50 51 static struct stot 52 { 53 const char *st_name; 54 int st_type; 55 } stot[] = 56 { 57 # if NETINET 58 { "A", T_A }, 59 # endif /* NETINET */ 60 # if NETINET6 61 { "AAAA", T_AAAA }, 62 # endif /* NETINET6 */ 63 { "NS", T_NS }, 64 { "CNAME", T_CNAME }, 65 { "PTR", T_PTR }, 66 { "MX", T_MX }, 67 { "TXT", T_TXT }, 68 { "AFSDB", T_AFSDB }, 69 { "SRV", T_SRV }, 70 { NULL, 0 } 71 }; 72 73 /* 74 ** DNS_STRING_TO_TYPE -- convert resource record name into type 75 ** 76 ** Parameters: 77 ** name -- name of resource record type 78 ** 79 ** Returns: 80 ** type if succeeded. 81 ** -1 otherwise. 82 */ 83 84 int 85 dns_string_to_type(name) 86 const char *name; 87 { 88 struct stot *p = stot; 89 90 for (p = stot; p->st_name != NULL; p++) 91 if (sm_strcasecmp(name, p->st_name) == 0) 92 return p->st_type; 93 return -1; 94 } 95 96 /* 97 ** DNS_TYPE_TO_STRING -- convert resource record type into name 98 ** 99 ** Parameters: 100 ** type -- resource record type 101 ** 102 ** Returns: 103 ** name if succeeded. 104 ** NULL otherwise. 105 */ 106 107 const char * 108 dns_type_to_string(type) 109 int type; 110 { 111 struct stot *p = stot; 112 113 for (p = stot; p->st_name != NULL; p++) 114 if (type == p->st_type) 115 return p->st_name; 116 return NULL; 117 } 118 119 /* 120 ** DNS_FREE_DATA -- free all components of a DNS_REPLY_T 121 ** 122 ** Parameters: 123 ** r -- pointer to DNS_REPLY_T 124 ** 125 ** Returns: 126 ** none. 127 */ 128 129 void 130 dns_free_data(r) 131 DNS_REPLY_T *r; 132 { 133 RESOURCE_RECORD_T *rr; 134 135 if (r->dns_r_q.dns_q_domain != NULL) 136 sm_free(r->dns_r_q.dns_q_domain); 137 for (rr = r->dns_r_head; rr != NULL; ) 138 { 139 RESOURCE_RECORD_T *tmp = rr; 140 141 if (rr->rr_domain != NULL) 142 sm_free(rr->rr_domain); 143 if (rr->rr_u.rr_data != NULL) 144 sm_free(rr->rr_u.rr_data); 145 rr = rr->rr_next; 146 sm_free(tmp); 147 } 148 sm_free(r); 149 } 150 151 /* 152 ** PARSE_DNS_REPLY -- parse DNS reply data. 153 ** 154 ** Parameters: 155 ** data -- pointer to dns data 156 ** len -- len of data 157 ** 158 ** Returns: 159 ** pointer to DNS_REPLY_T if succeeded. 160 ** NULL otherwise. 161 */ 162 163 static DNS_REPLY_T * 164 parse_dns_reply(data, len) 165 unsigned char *data; 166 int len; 167 { 168 unsigned char *p; 169 int status; 170 size_t l; 171 char host[MAXHOSTNAMELEN]; 172 DNS_REPLY_T *r; 173 RESOURCE_RECORD_T **rr; 174 175 r = (DNS_REPLY_T *) xalloc(sizeof(*r)); 176 memset(r, 0, sizeof(*r)); 177 if (r == NULL) 178 return NULL; 179 180 p = data; 181 182 /* doesn't work on Crays? */ 183 memcpy(&r->dns_r_h, p, sizeof(r->dns_r_h)); 184 p += sizeof(r->dns_r_h); 185 status = dn_expand(data, data + len, p, host, sizeof host); 186 if (status < 0) 187 { 188 dns_free_data(r); 189 return NULL; 190 } 191 r->dns_r_q.dns_q_domain = sm_strdup(host); 192 if (r->dns_r_q.dns_q_domain == NULL) 193 { 194 dns_free_data(r); 195 return NULL; 196 } 197 p += status; 198 GETSHORT(r->dns_r_q.dns_q_type, p); 199 GETSHORT(r->dns_r_q.dns_q_class, p); 200 rr = &r->dns_r_head; 201 while (p < data + len) 202 { 203 int type, class, ttl, size, txtlen; 204 205 status = dn_expand(data, data + len, p, host, sizeof host); 206 if (status < 0) 207 { 208 dns_free_data(r); 209 return NULL; 210 } 211 p += status; 212 GETSHORT(type, p); 213 GETSHORT(class, p); 214 GETLONG(ttl, p); 215 GETSHORT(size, p); 216 if (p + size > data + len) 217 { 218 /* 219 ** announced size of data exceeds length of 220 ** data paket: someone is cheating. 221 */ 222 223 if (LogLevel > 5) 224 sm_syslog(LOG_WARNING, NOQID, 225 "ERROR: DNS RDLENGTH=%d > data len=%d", 226 size, len - (p - data)); 227 dns_free_data(r); 228 return NULL; 229 } 230 *rr = (RESOURCE_RECORD_T *) xalloc(sizeof(**rr)); 231 if (*rr == NULL) 232 { 233 dns_free_data(r); 234 return NULL; 235 } 236 (*rr)->rr_domain = sm_strdup(host); 237 if ((*rr)->rr_domain == NULL) 238 { 239 dns_free_data(r); 240 return NULL; 241 } 242 (*rr)->rr_type = type; 243 (*rr)->rr_class = class; 244 (*rr)->rr_ttl = ttl; 245 (*rr)->rr_size = size; 246 switch (type) 247 { 248 case T_NS: 249 case T_CNAME: 250 case T_PTR: 251 status = dn_expand(data, data + len, p, host, 252 sizeof host); 253 if (status < 0) 254 { 255 dns_free_data(r); 256 return NULL; 257 } 258 (*rr)->rr_u.rr_txt = sm_strdup(host); 259 if ((*rr)->rr_u.rr_txt == NULL) 260 { 261 dns_free_data(r); 262 return NULL; 263 } 264 break; 265 266 case T_MX: 267 case T_AFSDB: 268 status = dn_expand(data, data + len, p + 2, host, 269 sizeof host); 270 if (status < 0) 271 { 272 dns_free_data(r); 273 return NULL; 274 } 275 l = strlen(host) + 1; 276 (*rr)->rr_u.rr_mx = (MX_RECORD_T *) 277 xalloc(sizeof(*((*rr)->rr_u.rr_mx)) + l); 278 if ((*rr)->rr_u.rr_mx == NULL) 279 { 280 dns_free_data(r); 281 return NULL; 282 } 283 (*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1]; 284 (void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain, 285 host, l); 286 break; 287 288 case T_SRV: 289 status = dn_expand(data, data + len, p + 6, host, 290 sizeof host); 291 if (status < 0) 292 { 293 dns_free_data(r); 294 return NULL; 295 } 296 l = strlen(host) + 1; 297 (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*) 298 xalloc(sizeof(*((*rr)->rr_u.rr_srv)) + l); 299 if ((*rr)->rr_u.rr_srv == NULL) 300 { 301 dns_free_data(r); 302 return NULL; 303 } 304 (*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1]; 305 (*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3]; 306 (*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5]; 307 (void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target, 308 host, l); 309 break; 310 311 case T_TXT: 312 313 /* 314 ** The TXT record contains the length as 315 ** leading byte, hence the value is restricted 316 ** to 255, which is less than the maximum value 317 ** of RDLENGTH (size). Nevertheless, txtlen 318 ** must be less than size because the latter 319 ** specifies the length of the entire TXT 320 ** record. 321 */ 322 323 txtlen = *p; 324 if (txtlen >= size) 325 { 326 if (LogLevel > 5) 327 sm_syslog(LOG_WARNING, NOQID, 328 "ERROR: DNS TXT record size=%d <= text len=%d", 329 size, txtlen); 330 dns_free_data(r); 331 return NULL; 332 } 333 (*rr)->rr_u.rr_txt = (char *) xalloc(txtlen + 1); 334 if ((*rr)->rr_u.rr_txt == NULL) 335 { 336 dns_free_data(r); 337 return NULL; 338 } 339 (void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1, 340 txtlen + 1); 341 break; 342 343 default: 344 (*rr)->rr_u.rr_data = (unsigned char*) xalloc(size); 345 if (size != 0 && (*rr)->rr_u.rr_data == NULL) 346 { 347 dns_free_data(r); 348 return NULL; 349 } 350 (void) memcpy((*rr)->rr_u.rr_data, p, size); 351 break; 352 } 353 p += size; 354 rr = &(*rr)->rr_next; 355 } 356 *rr = NULL; 357 return r; 358 } 359 360 /* 361 ** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine) 362 ** 363 ** Parameters: 364 ** domain -- name to lookup 365 ** rr_class -- resource record class 366 ** rr_type -- resource record type 367 ** retrans -- retransmission timeout 368 ** retry -- number of retries 369 ** 370 ** Returns: 371 ** result of lookup if succeeded. 372 ** NULL otherwise. 373 */ 374 375 DNS_REPLY_T * 376 dns_lookup_int(domain, rr_class, rr_type, retrans, retry) 377 const char *domain; 378 int rr_class; 379 int rr_type; 380 time_t retrans; 381 int retry; 382 { 383 int len; 384 unsigned long old_options = 0; 385 time_t save_retrans = 0; 386 int save_retry = 0; 387 DNS_REPLY_T *r = NULL; 388 unsigned char reply[1024]; 389 390 if (tTd(8, 16)) 391 { 392 old_options = _res.options; 393 _res.options |= RES_DEBUG; 394 sm_dprintf("dns_lookup(%s, %d, %s)\n", domain, 395 rr_class, dns_type_to_string(rr_type)); 396 } 397 if (retrans > 0) 398 { 399 save_retrans = _res.retrans; 400 _res.retrans = retrans; 401 } 402 if (retry > 0) 403 { 404 save_retry = _res.retry; 405 _res.retry = retry; 406 } 407 errno = 0; 408 SM_SET_H_ERRNO(0); 409 len = res_search(domain, rr_class, rr_type, reply, sizeof reply); 410 if (tTd(8, 16)) 411 { 412 _res.options = old_options; 413 sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n", 414 domain, rr_class, dns_type_to_string(rr_type), len); 415 } 416 if (len >= 0) 417 r = parse_dns_reply(reply, len); 418 if (retrans > 0) 419 _res.retrans = save_retrans; 420 if (retry > 0) 421 _res.retry = save_retry; 422 return r; 423 } 424 425 # if 0 426 DNS_REPLY_T * 427 dns_lookup(domain, type_name, retrans, retry) 428 const char *domain; 429 const char *type_name; 430 time_t retrans; 431 int retry; 432 { 433 int type; 434 435 type = dns_string_to_type(type_name); 436 if (type == -1) 437 { 438 if (tTd(8, 16)) 439 sm_dprintf("dns_lookup: unknown resource type: `%s'\n", 440 type_name); 441 return NULL; 442 } 443 return dns_lookup_int(domain, C_IN, type, retrans, retry); 444 } 445 # endif /* 0 */ 446 # endif /* NAMED_BIND */ 447 #endif /* DNSMAP */ 448