sm_resolve.c revision 112810
1295016Sjkim/* 2162911Ssimon * Copyright (c) 2000-2003 Sendmail, Inc. and its suppliers. 3162911Ssimon * All rights reserved. 4162911Ssimon * 5162911Ssimon * By using this file, you agree to the terms and conditions set 6162911Ssimon * forth in the LICENSE file which can be found at the top level of 7162911Ssimon * the sendmail distribution. 8162911Ssimon * 9162911Ssimon */ 10280304Sjkim 11162911Ssimon/* 12162911Ssimon * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan 13162911Ssimon * (Royal Institute of Technology, Stockholm, Sweden). 14162911Ssimon * All rights reserved. 15162911Ssimon * 16162911Ssimon * Redistribution and use in source and binary forms, with or without 17162911Ssimon * modification, are permitted provided that the following conditions 18162911Ssimon * are met: 19162911Ssimon * 20162911Ssimon * 1. Redistributions of source code must retain the above copyright 21162911Ssimon * notice, this list of conditions and the following disclaimer. 22162911Ssimon * 23162911Ssimon * 2. Redistributions in binary form must reproduce the above copyright 24162911Ssimon * notice, this list of conditions and the following disclaimer in the 25162911Ssimon * documentation and/or other materials provided with the distribution. 26162911Ssimon * 27162911Ssimon * 3. Neither the name of the Institute nor the names of its contributors 28162911Ssimon * may be used to endorse or promote products derived from this software 29162911Ssimon * without specific prior written permission. 30162911Ssimon * 31162911Ssimon * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 32162911Ssimon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33162911Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34162911Ssimon * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 35162911Ssimon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36162911Ssimon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37162911Ssimon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38162911Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39162911Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40162911Ssimon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41162911Ssimon * SUCH DAMAGE. 42162911Ssimon */ 43162911Ssimon 44162911Ssimon#include <sendmail.h> 45162911Ssimon#if DNSMAP 46162911Ssimon# if NAMED_BIND 47162911Ssimon# include "sm_resolve.h" 48162911Ssimon 49162911SsimonSM_RCSID("$Id: sm_resolve.c,v 8.24.4.7 2003/03/22 22:55:37 ca Exp $") 50162911Ssimon 51162911Ssimonstatic struct stot 52162911Ssimon{ 53162911Ssimon const char *st_name; 54162911Ssimon int st_type; 55162911Ssimon} stot[] = 56162911Ssimon{ 57280304Sjkim# if NETINET 58162911Ssimon { "A", T_A }, 59162911Ssimon# endif /* NETINET */ 60162911Ssimon# if NETINET6 61162911Ssimon { "AAAA", T_AAAA }, 62162911Ssimon# endif /* NETINET6 */ 63162911Ssimon { "NS", T_NS }, 64280304Sjkim { "CNAME", T_CNAME }, 65162911Ssimon { "PTR", T_PTR }, 66162911Ssimon { "MX", T_MX }, 67162911Ssimon { "TXT", T_TXT }, 68162911Ssimon { "AFSDB", T_AFSDB }, 69162911Ssimon { "SRV", T_SRV }, 70162911Ssimon { NULL, 0 } 71280304Sjkim}; 72162911Ssimon 73162911Ssimon/* 74162911Ssimon** DNS_STRING_TO_TYPE -- convert resource record name into type 75162911Ssimon** 76162911Ssimon** Parameters: 77162911Ssimon** name -- name of resource record type 78162911Ssimon** 79162911Ssimon** Returns: 80162911Ssimon** type if succeeded. 81162911Ssimon** -1 otherwise. 82162911Ssimon*/ 83162911Ssimon 84162911Ssimonint 85162911Ssimondns_string_to_type(name) 86280304Sjkim const char *name; 87162911Ssimon{ 88162911Ssimon struct stot *p = stot; 89280304Sjkim 90162911Ssimon for (p = stot; p->st_name != NULL; p++) 91162911Ssimon if (sm_strcasecmp(name, p->st_name) == 0) 92162911Ssimon return p->st_type; 93162911Ssimon return -1; 94162911Ssimon} 95162911Ssimon 96162911Ssimon/* 97162911Ssimon** DNS_TYPE_TO_STRING -- convert resource record type into name 98162911Ssimon** 99162911Ssimon** Parameters: 100162911Ssimon** type -- resource record type 101280304Sjkim** 102162911Ssimon** Returns: 103162911Ssimon** name if succeeded. 104162911Ssimon** NULL otherwise. 105162911Ssimon*/ 106162911Ssimon 107162911Ssimonconst char * 108162911Ssimondns_type_to_string(type) 109238405Sjkim int type; 110162911Ssimon{ 111280304Sjkim struct stot *p = stot; 112280304Sjkim 113280304Sjkim for (p = stot; p->st_name != NULL; p++) 114280304Sjkim if (type == p->st_type) 115162911Ssimon return p->st_name; 116162911Ssimon return NULL; 117162911Ssimon} 118280304Sjkim 119280304Sjkim/* 120280304Sjkim** DNS_FREE_DATA -- free all components of a DNS_REPLY_T 121162911Ssimon** 122280304Sjkim** Parameters: 123280304Sjkim** r -- pointer to DNS_REPLY_T 124280304Sjkim** 125162911Ssimon** Returns: 126162911Ssimon** none. 127162911Ssimon*/ 128280304Sjkim 129280304Sjkimvoid 130280304Sjkimdns_free_data(r) 131280304Sjkim DNS_REPLY_T *r; 132280304Sjkim{ 133280304Sjkim RESOURCE_RECORD_T *rr; 134162911Ssimon 135162911Ssimon if (r->dns_r_q.dns_q_domain != NULL) 136280304Sjkim sm_free(r->dns_r_q.dns_q_domain); 137280304Sjkim for (rr = r->dns_r_head; rr != NULL; ) 138280304Sjkim { 139280304Sjkim RESOURCE_RECORD_T *tmp = rr; 140280304Sjkim 141280304Sjkim 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 163static DNS_REPLY_T * 164parse_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 *) sm_malloc(sizeof(*r)); 176 if (r == NULL) 177 return NULL; 178 memset(r, 0, sizeof(*r)); 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 *) sm_malloc(sizeof(**rr)); 231 if (*rr == NULL) 232 { 233 dns_free_data(r); 234 return NULL; 235 } 236 memset(*rr, 0, sizeof(**rr)); 237 (*rr)->rr_domain = sm_strdup(host); 238 if ((*rr)->rr_domain == NULL) 239 { 240 dns_free_data(r); 241 return NULL; 242 } 243 (*rr)->rr_type = type; 244 (*rr)->rr_class = class; 245 (*rr)->rr_ttl = ttl; 246 (*rr)->rr_size = size; 247 switch (type) 248 { 249 case T_NS: 250 case T_CNAME: 251 case T_PTR: 252 status = dn_expand(data, data + len, p, host, 253 sizeof host); 254 if (status < 0) 255 { 256 dns_free_data(r); 257 return NULL; 258 } 259 (*rr)->rr_u.rr_txt = sm_strdup(host); 260 if ((*rr)->rr_u.rr_txt == NULL) 261 { 262 dns_free_data(r); 263 return NULL; 264 } 265 break; 266 267 case T_MX: 268 case T_AFSDB: 269 status = dn_expand(data, data + len, p + 2, host, 270 sizeof host); 271 if (status < 0) 272 { 273 dns_free_data(r); 274 return NULL; 275 } 276 l = strlen(host) + 1; 277 (*rr)->rr_u.rr_mx = (MX_RECORD_T *) 278 sm_malloc(sizeof(*((*rr)->rr_u.rr_mx)) + l); 279 if ((*rr)->rr_u.rr_mx == NULL) 280 { 281 dns_free_data(r); 282 return NULL; 283 } 284 (*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1]; 285 (void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain, 286 host, l); 287 break; 288 289 case T_SRV: 290 status = dn_expand(data, data + len, p + 6, host, 291 sizeof host); 292 if (status < 0) 293 { 294 dns_free_data(r); 295 return NULL; 296 } 297 l = strlen(host) + 1; 298 (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*) 299 sm_malloc(sizeof(*((*rr)->rr_u.rr_srv)) + l); 300 if ((*rr)->rr_u.rr_srv == NULL) 301 { 302 dns_free_data(r); 303 return NULL; 304 } 305 (*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1]; 306 (*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3]; 307 (*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5]; 308 (void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target, 309 host, l); 310 break; 311 312 case T_TXT: 313 314 /* 315 ** The TXT record contains the length as 316 ** leading byte, hence the value is restricted 317 ** to 255, which is less than the maximum value 318 ** of RDLENGTH (size). Nevertheless, txtlen 319 ** must be less than size because the latter 320 ** specifies the length of the entire TXT 321 ** record. 322 */ 323 324 txtlen = *p; 325 if (txtlen >= size) 326 { 327 if (LogLevel > 5) 328 sm_syslog(LOG_WARNING, NOQID, 329 "ERROR: DNS TXT record size=%d <= text len=%d", 330 size, txtlen); 331 dns_free_data(r); 332 return NULL; 333 } 334 (*rr)->rr_u.rr_txt = (char *) sm_malloc(txtlen + 1); 335 if ((*rr)->rr_u.rr_txt == NULL) 336 { 337 dns_free_data(r); 338 return NULL; 339 } 340 (void) sm_strlcpy((*rr)->rr_u.rr_txt, (char*) p + 1, 341 txtlen + 1); 342 break; 343 344 default: 345 (*rr)->rr_u.rr_data = (unsigned char*) sm_malloc(size); 346 if ((*rr)->rr_u.rr_data == NULL) 347 { 348 dns_free_data(r); 349 return NULL; 350 } 351 (void) memcpy((*rr)->rr_u.rr_data, p, size); 352 break; 353 } 354 p += size; 355 rr = &(*rr)->rr_next; 356 } 357 *rr = NULL; 358 return r; 359} 360 361/* 362** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine) 363** 364** Parameters: 365** domain -- name to lookup 366** rr_class -- resource record class 367** rr_type -- resource record type 368** retrans -- retransmission timeout 369** retry -- number of retries 370** 371** Returns: 372** result of lookup if succeeded. 373** NULL otherwise. 374*/ 375 376DNS_REPLY_T * 377dns_lookup_int(domain, rr_class, rr_type, retrans, retry) 378 const char *domain; 379 int rr_class; 380 int rr_type; 381 time_t retrans; 382 int retry; 383{ 384 int len; 385 unsigned long old_options = 0; 386 time_t save_retrans = 0; 387 int save_retry = 0; 388 DNS_REPLY_T *r = NULL; 389 unsigned char reply[1024]; 390 391 if (tTd(8, 16)) 392 { 393 old_options = _res.options; 394 _res.options |= RES_DEBUG; 395 sm_dprintf("dns_lookup(%s, %d, %s)\n", domain, 396 rr_class, dns_type_to_string(rr_type)); 397 } 398 if (retrans > 0) 399 { 400 save_retrans = _res.retrans; 401 _res.retrans = retrans; 402 } 403 if (retry > 0) 404 { 405 save_retry = _res.retry; 406 _res.retry = retry; 407 } 408 errno = 0; 409 SM_SET_H_ERRNO(0); 410 len = res_search(domain, rr_class, rr_type, reply, sizeof reply); 411 if (tTd(8, 16)) 412 { 413 _res.options = old_options; 414 sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n", 415 domain, rr_class, dns_type_to_string(rr_type), len); 416 } 417 if (len >= 0) 418 r = parse_dns_reply(reply, len); 419 if (retrans > 0) 420 _res.retrans = save_retrans; 421 if (retry > 0) 422 _res.retry = save_retry; 423 return r; 424} 425 426# if 0 427DNS_REPLY_T * 428dns_lookup(domain, type_name, retrans, retry) 429 const char *domain; 430 const char *type_name; 431 time_t retrans; 432 int retry; 433{ 434 int type; 435 436 type = dns_string_to_type(type_name); 437 if (type == -1) 438 { 439 if (tTd(8, 16)) 440 sm_dprintf("dns_lookup: unknown resource type: `%s'\n", 441 type_name); 442 return NULL; 443 } 444 return dns_lookup_int(domain, C_IN, type, retrans, retry); 445} 446# endif /* 0 */ 447# endif /* NAMED_BIND */ 448#endif /* DNSMAP */ 449