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