sm_resolve.c revision 90792
190792Sgshapiro/* 290792Sgshapiro * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro * 990792Sgshapiro */ 1090792Sgshapiro 1190792Sgshapiro/* 1290792Sgshapiro * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan 1390792Sgshapiro * (Royal Institute of Technology, Stockholm, Sweden). 1490792Sgshapiro * All rights reserved. 1590792Sgshapiro * 1690792Sgshapiro * Redistribution and use in source and binary forms, with or without 1790792Sgshapiro * modification, are permitted provided that the following conditions 1890792Sgshapiro * are met: 1990792Sgshapiro * 2090792Sgshapiro * 1. Redistributions of source code must retain the above copyright 2190792Sgshapiro * notice, this list of conditions and the following disclaimer. 2290792Sgshapiro * 2390792Sgshapiro * 2. Redistributions in binary form must reproduce the above copyright 2490792Sgshapiro * notice, this list of conditions and the following disclaimer in the 2590792Sgshapiro * documentation and/or other materials provided with the distribution. 2690792Sgshapiro * 2790792Sgshapiro * 3. Neither the name of the Institute nor the names of its contributors 2890792Sgshapiro * may be used to endorse or promote products derived from this software 2990792Sgshapiro * without specific prior written permission. 3090792Sgshapiro * 3190792Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 3290792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3390792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3490792Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 3590792Sgshapiro * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3690792Sgshapiro * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3790792Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3890792Sgshapiro * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3990792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4090792Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4190792Sgshapiro * SUCH DAMAGE. 4290792Sgshapiro */ 4390792Sgshapiro 4490792Sgshapiro#include <sendmail.h> 4590792Sgshapiro#if DNSMAP 4690792Sgshapiro# if NAMED_BIND 4790792Sgshapiro# include "sm_resolve.h" 4890792Sgshapiro 4990792SgshapiroSM_RCSID("$Id: sm_resolve.c,v 8.24 2001/09/11 04:05:16 gshapiro Exp $") 5090792Sgshapiro 5190792Sgshapirostatic struct stot 5290792Sgshapiro{ 5390792Sgshapiro const char *st_name; 5490792Sgshapiro int st_type; 5590792Sgshapiro} stot[] = 5690792Sgshapiro{ 5790792Sgshapiro# if NETINET 5890792Sgshapiro { "A", T_A }, 5990792Sgshapiro# endif /* NETINET */ 6090792Sgshapiro# if NETINET6 6190792Sgshapiro { "AAAA", T_AAAA }, 6290792Sgshapiro# endif /* NETINET6 */ 6390792Sgshapiro { "NS", T_NS }, 6490792Sgshapiro { "CNAME", T_CNAME }, 6590792Sgshapiro { "PTR", T_PTR }, 6690792Sgshapiro { "MX", T_MX }, 6790792Sgshapiro { "TXT", T_TXT }, 6890792Sgshapiro { "AFSDB", T_AFSDB }, 6990792Sgshapiro { "SRV", T_SRV }, 7090792Sgshapiro { NULL, 0 } 7190792Sgshapiro}; 7290792Sgshapiro 7390792Sgshapiro/* 7490792Sgshapiro** DNS_STRING_TO_TYPE -- convert resource record name into type 7590792Sgshapiro** 7690792Sgshapiro** Parameters: 7790792Sgshapiro** name -- name of resource record type 7890792Sgshapiro** 7990792Sgshapiro** Returns: 8090792Sgshapiro** type if succeeded. 8190792Sgshapiro** -1 otherwise. 8290792Sgshapiro*/ 8390792Sgshapiro 8490792Sgshapiroint 8590792Sgshapirodns_string_to_type(name) 8690792Sgshapiro const char *name; 8790792Sgshapiro{ 8890792Sgshapiro struct stot *p = stot; 8990792Sgshapiro 9090792Sgshapiro for (p = stot; p->st_name != NULL; p++) 9190792Sgshapiro if (sm_strcasecmp(name, p->st_name) == 0) 9290792Sgshapiro return p->st_type; 9390792Sgshapiro return -1; 9490792Sgshapiro} 9590792Sgshapiro 9690792Sgshapiro/* 9790792Sgshapiro** DNS_TYPE_TO_STRING -- convert resource record type into name 9890792Sgshapiro** 9990792Sgshapiro** Parameters: 10090792Sgshapiro** type -- resource record type 10190792Sgshapiro** 10290792Sgshapiro** Returns: 10390792Sgshapiro** name if succeeded. 10490792Sgshapiro** NULL otherwise. 10590792Sgshapiro*/ 10690792Sgshapiro 10790792Sgshapiroconst char * 10890792Sgshapirodns_type_to_string(type) 10990792Sgshapiro int type; 11090792Sgshapiro{ 11190792Sgshapiro struct stot *p = stot; 11290792Sgshapiro 11390792Sgshapiro for (p = stot; p->st_name != NULL; p++) 11490792Sgshapiro if (type == p->st_type) 11590792Sgshapiro return p->st_name; 11690792Sgshapiro return NULL; 11790792Sgshapiro} 11890792Sgshapiro 11990792Sgshapiro/* 12090792Sgshapiro** DNS_FREE_DATA -- free all components of a DNS_REPLY_T 12190792Sgshapiro** 12290792Sgshapiro** Parameters: 12390792Sgshapiro** r -- pointer to DNS_REPLY_T 12490792Sgshapiro** 12590792Sgshapiro** Returns: 12690792Sgshapiro** none. 12790792Sgshapiro*/ 12890792Sgshapiro 12990792Sgshapirovoid 13090792Sgshapirodns_free_data(r) 13190792Sgshapiro DNS_REPLY_T *r; 13290792Sgshapiro{ 13390792Sgshapiro RESOURCE_RECORD_T *rr; 13490792Sgshapiro 13590792Sgshapiro if (r->dns_r_q.dns_q_domain != NULL) 13690792Sgshapiro sm_free(r->dns_r_q.dns_q_domain); 13790792Sgshapiro for (rr = r->dns_r_head; rr != NULL; ) 13890792Sgshapiro { 13990792Sgshapiro RESOURCE_RECORD_T *tmp = rr; 14090792Sgshapiro 14190792Sgshapiro if (rr->rr_domain != NULL) 14290792Sgshapiro sm_free(rr->rr_domain); 14390792Sgshapiro if (rr->rr_u.rr_data != NULL) 14490792Sgshapiro sm_free(rr->rr_u.rr_data); 14590792Sgshapiro rr = rr->rr_next; 14690792Sgshapiro sm_free(tmp); 14790792Sgshapiro } 14890792Sgshapiro sm_free(r); 14990792Sgshapiro} 15090792Sgshapiro 15190792Sgshapiro/* 15290792Sgshapiro** PARSE_DNS_REPLY -- parse DNS reply data. 15390792Sgshapiro** 15490792Sgshapiro** Parameters: 15590792Sgshapiro** data -- pointer to dns data 15690792Sgshapiro** len -- len of data 15790792Sgshapiro** 15890792Sgshapiro** Returns: 15990792Sgshapiro** pointer to DNS_REPLY_T if succeeded. 16090792Sgshapiro** NULL otherwise. 16190792Sgshapiro*/ 16290792Sgshapiro 16390792Sgshapirostatic DNS_REPLY_T * 16490792Sgshapiroparse_dns_reply(data, len) 16590792Sgshapiro unsigned char *data; 16690792Sgshapiro int len; 16790792Sgshapiro{ 16890792Sgshapiro unsigned char *p; 16990792Sgshapiro int status; 17090792Sgshapiro size_t l; 17190792Sgshapiro char host[MAXHOSTNAMELEN]; 17290792Sgshapiro DNS_REPLY_T *r; 17390792Sgshapiro RESOURCE_RECORD_T **rr; 17490792Sgshapiro 17590792Sgshapiro r = (DNS_REPLY_T *) xalloc(sizeof(*r)); 17690792Sgshapiro memset(r, 0, sizeof(*r)); 17790792Sgshapiro if (r == NULL) 17890792Sgshapiro return NULL; 17990792Sgshapiro 18090792Sgshapiro p = data; 18190792Sgshapiro 18290792Sgshapiro /* doesn't work on Crays? */ 18390792Sgshapiro memcpy(&r->dns_r_h, p, sizeof(HEADER)); 18490792Sgshapiro p += sizeof(HEADER); 18590792Sgshapiro status = dn_expand(data, data + len, p, host, sizeof host); 18690792Sgshapiro if (status < 0) 18790792Sgshapiro { 18890792Sgshapiro dns_free_data(r); 18990792Sgshapiro return NULL; 19090792Sgshapiro } 19190792Sgshapiro r->dns_r_q.dns_q_domain = sm_strdup(host); 19290792Sgshapiro if (r->dns_r_q.dns_q_domain == NULL) 19390792Sgshapiro { 19490792Sgshapiro dns_free_data(r); 19590792Sgshapiro return NULL; 19690792Sgshapiro } 19790792Sgshapiro p += status; 19890792Sgshapiro GETSHORT(r->dns_r_q.dns_q_type, p); 19990792Sgshapiro GETSHORT(r->dns_r_q.dns_q_class, p); 20090792Sgshapiro rr = &r->dns_r_head; 20190792Sgshapiro while (p < data + len) 20290792Sgshapiro { 20390792Sgshapiro int type, class, ttl, size; 20490792Sgshapiro 20590792Sgshapiro status = dn_expand(data, data + len, p, host, sizeof host); 20690792Sgshapiro if (status < 0) 20790792Sgshapiro { 20890792Sgshapiro dns_free_data(r); 20990792Sgshapiro return NULL; 21090792Sgshapiro } 21190792Sgshapiro p += status; 21290792Sgshapiro GETSHORT(type, p); 21390792Sgshapiro GETSHORT(class, p); 21490792Sgshapiro GETLONG(ttl, p); 21590792Sgshapiro GETSHORT(size, p); 21690792Sgshapiro *rr = (RESOURCE_RECORD_T *) xalloc(sizeof(RESOURCE_RECORD_T)); 21790792Sgshapiro if (*rr == NULL) 21890792Sgshapiro { 21990792Sgshapiro dns_free_data(r); 22090792Sgshapiro return NULL; 22190792Sgshapiro } 22290792Sgshapiro (*rr)->rr_domain = sm_strdup(host); 22390792Sgshapiro if ((*rr)->rr_domain == NULL) 22490792Sgshapiro { 22590792Sgshapiro dns_free_data(r); 22690792Sgshapiro return NULL; 22790792Sgshapiro } 22890792Sgshapiro (*rr)->rr_type = type; 22990792Sgshapiro (*rr)->rr_class = class; 23090792Sgshapiro (*rr)->rr_ttl = ttl; 23190792Sgshapiro (*rr)->rr_size = size; 23290792Sgshapiro switch (type) 23390792Sgshapiro { 23490792Sgshapiro case T_NS: 23590792Sgshapiro case T_CNAME: 23690792Sgshapiro case T_PTR: 23790792Sgshapiro status = dn_expand(data, data + len, p, host, 23890792Sgshapiro sizeof host); 23990792Sgshapiro if (status < 0) 24090792Sgshapiro { 24190792Sgshapiro dns_free_data(r); 24290792Sgshapiro return NULL; 24390792Sgshapiro } 24490792Sgshapiro (*rr)->rr_u.rr_txt = sm_strdup(host); 24590792Sgshapiro if ((*rr)->rr_u.rr_txt == NULL) 24690792Sgshapiro { 24790792Sgshapiro dns_free_data(r); 24890792Sgshapiro return NULL; 24990792Sgshapiro } 25090792Sgshapiro break; 25190792Sgshapiro 25290792Sgshapiro case T_MX: 25390792Sgshapiro case T_AFSDB: 25490792Sgshapiro status = dn_expand(data, data + len, p + 2, host, 25590792Sgshapiro sizeof host); 25690792Sgshapiro if (status < 0) 25790792Sgshapiro { 25890792Sgshapiro dns_free_data(r); 25990792Sgshapiro return NULL; 26090792Sgshapiro } 26190792Sgshapiro l = strlen(host) + 1; 26290792Sgshapiro (*rr)->rr_u.rr_mx = (MX_RECORD_T *) 26390792Sgshapiro xalloc(sizeof(MX_RECORD_T) + l); 26490792Sgshapiro if ((*rr)->rr_u.rr_mx == NULL) 26590792Sgshapiro { 26690792Sgshapiro dns_free_data(r); 26790792Sgshapiro return NULL; 26890792Sgshapiro } 26990792Sgshapiro (*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1]; 27090792Sgshapiro (void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain, 27190792Sgshapiro host, l); 27290792Sgshapiro break; 27390792Sgshapiro 27490792Sgshapiro case T_SRV: 27590792Sgshapiro status = dn_expand(data, data + len, p + 6, host, 27690792Sgshapiro sizeof host); 27790792Sgshapiro if (status < 0) 27890792Sgshapiro { 27990792Sgshapiro dns_free_data(r); 28090792Sgshapiro return NULL; 28190792Sgshapiro } 28290792Sgshapiro l = strlen(host) + 1; 28390792Sgshapiro (*rr)->rr_u.rr_srv = (SRV_RECORDT_T*) 28490792Sgshapiro xalloc(sizeof(SRV_RECORDT_T) + l); 28590792Sgshapiro if ((*rr)->rr_u.rr_srv == NULL) 28690792Sgshapiro { 28790792Sgshapiro dns_free_data(r); 28890792Sgshapiro return NULL; 28990792Sgshapiro } 29090792Sgshapiro (*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1]; 29190792Sgshapiro (*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3]; 29290792Sgshapiro (*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5]; 29390792Sgshapiro (void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target, 29490792Sgshapiro host, l); 29590792Sgshapiro break; 29690792Sgshapiro 29790792Sgshapiro case T_TXT: 29890792Sgshapiro (*rr)->rr_u.rr_txt = (char *) xalloc(size + 1); 29990792Sgshapiro if ((*rr)->rr_u.rr_txt == NULL) 30090792Sgshapiro { 30190792Sgshapiro dns_free_data(r); 30290792Sgshapiro return NULL; 30390792Sgshapiro } 30490792Sgshapiro (void) strncpy((*rr)->rr_u.rr_txt, (char*) p + 1, *p); 30590792Sgshapiro (*rr)->rr_u.rr_txt[*p] = 0; 30690792Sgshapiro break; 30790792Sgshapiro 30890792Sgshapiro default: 30990792Sgshapiro (*rr)->rr_u.rr_data = (unsigned char*) xalloc(size); 31090792Sgshapiro if (size != 0 && (*rr)->rr_u.rr_data == NULL) 31190792Sgshapiro { 31290792Sgshapiro dns_free_data(r); 31390792Sgshapiro return NULL; 31490792Sgshapiro } 31590792Sgshapiro (void) memcpy((*rr)->rr_u.rr_data, p, size); 31690792Sgshapiro } 31790792Sgshapiro p += size; 31890792Sgshapiro rr = &(*rr)->rr_next; 31990792Sgshapiro } 32090792Sgshapiro *rr = NULL; 32190792Sgshapiro return r; 32290792Sgshapiro} 32390792Sgshapiro 32490792Sgshapiro/* 32590792Sgshapiro** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine) 32690792Sgshapiro** 32790792Sgshapiro** Parameters: 32890792Sgshapiro** domain -- name to lookup 32990792Sgshapiro** rr_class -- resource record class 33090792Sgshapiro** rr_type -- resource record type 33190792Sgshapiro** retrans -- retransmission timeout 33290792Sgshapiro** retry -- number of retries 33390792Sgshapiro** 33490792Sgshapiro** Returns: 33590792Sgshapiro** result of lookup if succeeded. 33690792Sgshapiro** NULL otherwise. 33790792Sgshapiro*/ 33890792Sgshapiro 33990792SgshapiroDNS_REPLY_T * 34090792Sgshapirodns_lookup_int(domain, rr_class, rr_type, retrans, retry) 34190792Sgshapiro const char *domain; 34290792Sgshapiro int rr_class; 34390792Sgshapiro int rr_type; 34490792Sgshapiro time_t retrans; 34590792Sgshapiro int retry; 34690792Sgshapiro{ 34790792Sgshapiro int len; 34890792Sgshapiro unsigned long old_options = 0; 34990792Sgshapiro time_t save_retrans = 0; 35090792Sgshapiro int save_retry = 0; 35190792Sgshapiro DNS_REPLY_T *r = NULL; 35290792Sgshapiro unsigned char reply[1024]; 35390792Sgshapiro 35490792Sgshapiro if (tTd(8, 16)) 35590792Sgshapiro { 35690792Sgshapiro old_options = _res.options; 35790792Sgshapiro _res.options |= RES_DEBUG; 35890792Sgshapiro sm_dprintf("dns_lookup(%s, %d, %s)\n", domain, 35990792Sgshapiro rr_class, dns_type_to_string(rr_type)); 36090792Sgshapiro } 36190792Sgshapiro if (retrans > 0) 36290792Sgshapiro { 36390792Sgshapiro save_retrans = _res.retrans; 36490792Sgshapiro _res.retrans = retrans; 36590792Sgshapiro } 36690792Sgshapiro if (retry > 0) 36790792Sgshapiro { 36890792Sgshapiro save_retry = _res.retry; 36990792Sgshapiro _res.retry = retry; 37090792Sgshapiro } 37190792Sgshapiro errno = 0; 37290792Sgshapiro SM_SET_H_ERRNO(0); 37390792Sgshapiro len = res_search(domain, rr_class, rr_type, reply, sizeof reply); 37490792Sgshapiro if (tTd(8, 16)) 37590792Sgshapiro { 37690792Sgshapiro _res.options = old_options; 37790792Sgshapiro sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n", 37890792Sgshapiro domain, rr_class, dns_type_to_string(rr_type), len); 37990792Sgshapiro } 38090792Sgshapiro if (len >= 0) 38190792Sgshapiro r = parse_dns_reply(reply, len); 38290792Sgshapiro if (retrans > 0) 38390792Sgshapiro _res.retrans = save_retrans; 38490792Sgshapiro if (retry > 0) 38590792Sgshapiro _res.retry = save_retry; 38690792Sgshapiro return r; 38790792Sgshapiro} 38890792Sgshapiro 38990792Sgshapiro# if 0 39090792SgshapiroDNS_REPLY_T * 39190792Sgshapirodns_lookup(domain, type_name, retrans, retry) 39290792Sgshapiro const char *domain; 39390792Sgshapiro const char *type_name; 39490792Sgshapiro time_t retrans; 39590792Sgshapiro int retry; 39690792Sgshapiro{ 39790792Sgshapiro int type; 39890792Sgshapiro 39990792Sgshapiro type = dns_string_to_type(type_name); 40090792Sgshapiro if (type == -1) 40190792Sgshapiro { 40290792Sgshapiro if (tTd(8, 16)) 40390792Sgshapiro sm_dprintf("dns_lookup: unknown resource type: `%s'\n", 40490792Sgshapiro type_name); 40590792Sgshapiro return NULL; 40690792Sgshapiro } 40790792Sgshapiro return dns_lookup_int(domain, C_IN, type, retrans, retry); 40890792Sgshapiro} 40990792Sgshapiro# endif /* 0 */ 41090792Sgshapiro# endif /* NAMED_BIND */ 41190792Sgshapiro#endif /* DNSMAP */ 412