2002-02-17 21:56:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* By using this file, you agree to the terms and conditions set
|
|
|
|
|
* forth in the LICENSE file which can be found at the top level of
|
|
|
|
|
* the sendmail distribution.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H<EFBFBD>gskolan
|
|
|
|
|
* (Royal Institute of Technology, Stockholm, Sweden).
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
|
* are met:
|
|
|
|
|
*
|
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
|
*
|
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
|
*
|
|
|
|
|
* 3. Neither the name of the Institute nor the names of its contributors
|
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
|
* without specific prior written permission.
|
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <sendmail.h>
|
|
|
|
|
#if DNSMAP
|
|
|
|
|
# if NAMED_BIND
|
|
|
|
|
# include "sm_resolve.h"
|
|
|
|
|
|
2002-06-11 21:12:04 +00:00
|
|
|
|
SM_RCSID("$Id: sm_resolve.c,v 8.24 2001/09/11 04:05:16 gshapiro Exp $")
|
2002-02-17 21:56:45 +00:00
|
|
|
|
|
|
|
|
|
static struct stot
|
|
|
|
|
{
|
|
|
|
|
const char *st_name;
|
|
|
|
|
int st_type;
|
|
|
|
|
} stot[] =
|
|
|
|
|
{
|
|
|
|
|
# if NETINET
|
|
|
|
|
{ "A", T_A },
|
|
|
|
|
# endif /* NETINET */
|
|
|
|
|
# if NETINET6
|
|
|
|
|
{ "AAAA", T_AAAA },
|
|
|
|
|
# endif /* NETINET6 */
|
|
|
|
|
{ "NS", T_NS },
|
|
|
|
|
{ "CNAME", T_CNAME },
|
|
|
|
|
{ "PTR", T_PTR },
|
|
|
|
|
{ "MX", T_MX },
|
|
|
|
|
{ "TXT", T_TXT },
|
|
|
|
|
{ "AFSDB", T_AFSDB },
|
|
|
|
|
{ "SRV", T_SRV },
|
|
|
|
|
{ NULL, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** DNS_STRING_TO_TYPE -- convert resource record name into type
|
|
|
|
|
**
|
|
|
|
|
** Parameters:
|
|
|
|
|
** name -- name of resource record type
|
|
|
|
|
**
|
|
|
|
|
** Returns:
|
|
|
|
|
** type if succeeded.
|
|
|
|
|
** -1 otherwise.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
dns_string_to_type(name)
|
|
|
|
|
const char *name;
|
|
|
|
|
{
|
|
|
|
|
struct stot *p = stot;
|
|
|
|
|
|
|
|
|
|
for (p = stot; p->st_name != NULL; p++)
|
|
|
|
|
if (sm_strcasecmp(name, p->st_name) == 0)
|
|
|
|
|
return p->st_type;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** DNS_TYPE_TO_STRING -- convert resource record type into name
|
|
|
|
|
**
|
|
|
|
|
** Parameters:
|
|
|
|
|
** type -- resource record type
|
|
|
|
|
**
|
|
|
|
|
** Returns:
|
|
|
|
|
** name if succeeded.
|
|
|
|
|
** NULL otherwise.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
dns_type_to_string(type)
|
|
|
|
|
int type;
|
|
|
|
|
{
|
|
|
|
|
struct stot *p = stot;
|
|
|
|
|
|
|
|
|
|
for (p = stot; p->st_name != NULL; p++)
|
|
|
|
|
if (type == p->st_type)
|
|
|
|
|
return p->st_name;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** DNS_FREE_DATA -- free all components of a DNS_REPLY_T
|
|
|
|
|
**
|
|
|
|
|
** Parameters:
|
|
|
|
|
** r -- pointer to DNS_REPLY_T
|
|
|
|
|
**
|
|
|
|
|
** Returns:
|
|
|
|
|
** none.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dns_free_data(r)
|
|
|
|
|
DNS_REPLY_T *r;
|
|
|
|
|
{
|
|
|
|
|
RESOURCE_RECORD_T *rr;
|
|
|
|
|
|
|
|
|
|
if (r->dns_r_q.dns_q_domain != NULL)
|
|
|
|
|
sm_free(r->dns_r_q.dns_q_domain);
|
|
|
|
|
for (rr = r->dns_r_head; rr != NULL; )
|
|
|
|
|
{
|
|
|
|
|
RESOURCE_RECORD_T *tmp = rr;
|
|
|
|
|
|
|
|
|
|
if (rr->rr_domain != NULL)
|
|
|
|
|
sm_free(rr->rr_domain);
|
|
|
|
|
if (rr->rr_u.rr_data != NULL)
|
|
|
|
|
sm_free(rr->rr_u.rr_data);
|
|
|
|
|
rr = rr->rr_next;
|
|
|
|
|
sm_free(tmp);
|
|
|
|
|
}
|
|
|
|
|
sm_free(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** PARSE_DNS_REPLY -- parse DNS reply data.
|
|
|
|
|
**
|
|
|
|
|
** Parameters:
|
|
|
|
|
** data -- pointer to dns data
|
|
|
|
|
** len -- len of data
|
|
|
|
|
**
|
|
|
|
|
** Returns:
|
|
|
|
|
** pointer to DNS_REPLY_T if succeeded.
|
|
|
|
|
** NULL otherwise.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static DNS_REPLY_T *
|
|
|
|
|
parse_dns_reply(data, len)
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
int len;
|
|
|
|
|
{
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
int status;
|
|
|
|
|
size_t l;
|
|
|
|
|
char host[MAXHOSTNAMELEN];
|
|
|
|
|
DNS_REPLY_T *r;
|
|
|
|
|
RESOURCE_RECORD_T **rr;
|
|
|
|
|
|
|
|
|
|
r = (DNS_REPLY_T *) xalloc(sizeof(*r));
|
|
|
|
|
memset(r, 0, sizeof(*r));
|
|
|
|
|
if (r == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
p = data;
|
|
|
|
|
|
|
|
|
|
/* doesn't work on Crays? */
|
|
|
|
|
memcpy(&r->dns_r_h, p, sizeof(HEADER));
|
|
|
|
|
p += sizeof(HEADER);
|
|
|
|
|
status = dn_expand(data, data + len, p, host, sizeof host);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
r->dns_r_q.dns_q_domain = sm_strdup(host);
|
|
|
|
|
if (r->dns_r_q.dns_q_domain == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
p += status;
|
|
|
|
|
GETSHORT(r->dns_r_q.dns_q_type, p);
|
|
|
|
|
GETSHORT(r->dns_r_q.dns_q_class, p);
|
|
|
|
|
rr = &r->dns_r_head;
|
|
|
|
|
while (p < data + len)
|
|
|
|
|
{
|
|
|
|
|
int type, class, ttl, size;
|
|
|
|
|
|
|
|
|
|
status = dn_expand(data, data + len, p, host, sizeof host);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
p += status;
|
|
|
|
|
GETSHORT(type, p);
|
|
|
|
|
GETSHORT(class, p);
|
|
|
|
|
GETLONG(ttl, p);
|
|
|
|
|
GETSHORT(size, p);
|
|
|
|
|
*rr = (RESOURCE_RECORD_T *) xalloc(sizeof(RESOURCE_RECORD_T));
|
|
|
|
|
if (*rr == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(*rr)->rr_domain = sm_strdup(host);
|
|
|
|
|
if ((*rr)->rr_domain == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(*rr)->rr_type = type;
|
|
|
|
|
(*rr)->rr_class = class;
|
|
|
|
|
(*rr)->rr_ttl = ttl;
|
|
|
|
|
(*rr)->rr_size = size;
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
|
|
|
|
case T_NS:
|
|
|
|
|
case T_CNAME:
|
|
|
|
|
case T_PTR:
|
|
|
|
|
status = dn_expand(data, data + len, p, host,
|
|
|
|
|
sizeof host);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(*rr)->rr_u.rr_txt = sm_strdup(host);
|
|
|
|
|
if ((*rr)->rr_u.rr_txt == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_MX:
|
|
|
|
|
case T_AFSDB:
|
|
|
|
|
status = dn_expand(data, data + len, p + 2, host,
|
|
|
|
|
sizeof host);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
l = strlen(host) + 1;
|
|
|
|
|
(*rr)->rr_u.rr_mx = (MX_RECORD_T *)
|
|
|
|
|
xalloc(sizeof(MX_RECORD_T) + l);
|
|
|
|
|
if ((*rr)->rr_u.rr_mx == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(*rr)->rr_u.rr_mx->mx_r_preference = (p[0] << 8) | p[1];
|
|
|
|
|
(void) sm_strlcpy((*rr)->rr_u.rr_mx->mx_r_domain,
|
|
|
|
|
host, l);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_SRV:
|
|
|
|
|
status = dn_expand(data, data + len, p + 6, host,
|
|
|
|
|
sizeof host);
|
|
|
|
|
if (status < 0)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
l = strlen(host) + 1;
|
|
|
|
|
(*rr)->rr_u.rr_srv = (SRV_RECORDT_T*)
|
|
|
|
|
xalloc(sizeof(SRV_RECORDT_T) + l);
|
|
|
|
|
if ((*rr)->rr_u.rr_srv == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(*rr)->rr_u.rr_srv->srv_r_priority = (p[0] << 8) | p[1];
|
|
|
|
|
(*rr)->rr_u.rr_srv->srv_r_weight = (p[2] << 8) | p[3];
|
|
|
|
|
(*rr)->rr_u.rr_srv->srv_r_port = (p[4] << 8) | p[5];
|
|
|
|
|
(void) sm_strlcpy((*rr)->rr_u.rr_srv->srv_r_target,
|
|
|
|
|
host, l);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_TXT:
|
|
|
|
|
(*rr)->rr_u.rr_txt = (char *) xalloc(size + 1);
|
|
|
|
|
if ((*rr)->rr_u.rr_txt == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(void) strncpy((*rr)->rr_u.rr_txt, (char*) p + 1, *p);
|
|
|
|
|
(*rr)->rr_u.rr_txt[*p] = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
(*rr)->rr_u.rr_data = (unsigned char*) xalloc(size);
|
|
|
|
|
if (size != 0 && (*rr)->rr_u.rr_data == NULL)
|
|
|
|
|
{
|
|
|
|
|
dns_free_data(r);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
(void) memcpy((*rr)->rr_u.rr_data, p, size);
|
|
|
|
|
}
|
|
|
|
|
p += size;
|
|
|
|
|
rr = &(*rr)->rr_next;
|
|
|
|
|
}
|
|
|
|
|
*rr = NULL;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** DNS_LOOKUP_INT -- perform dns map lookup (internal helper routine)
|
|
|
|
|
**
|
|
|
|
|
** Parameters:
|
|
|
|
|
** domain -- name to lookup
|
|
|
|
|
** rr_class -- resource record class
|
|
|
|
|
** rr_type -- resource record type
|
|
|
|
|
** retrans -- retransmission timeout
|
|
|
|
|
** retry -- number of retries
|
|
|
|
|
**
|
|
|
|
|
** Returns:
|
|
|
|
|
** result of lookup if succeeded.
|
|
|
|
|
** NULL otherwise.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
DNS_REPLY_T *
|
|
|
|
|
dns_lookup_int(domain, rr_class, rr_type, retrans, retry)
|
|
|
|
|
const char *domain;
|
|
|
|
|
int rr_class;
|
|
|
|
|
int rr_type;
|
|
|
|
|
time_t retrans;
|
|
|
|
|
int retry;
|
|
|
|
|
{
|
|
|
|
|
int len;
|
|
|
|
|
unsigned long old_options = 0;
|
|
|
|
|
time_t save_retrans = 0;
|
|
|
|
|
int save_retry = 0;
|
|
|
|
|
DNS_REPLY_T *r = NULL;
|
|
|
|
|
unsigned char reply[1024];
|
|
|
|
|
|
|
|
|
|
if (tTd(8, 16))
|
|
|
|
|
{
|
|
|
|
|
old_options = _res.options;
|
|
|
|
|
_res.options |= RES_DEBUG;
|
|
|
|
|
sm_dprintf("dns_lookup(%s, %d, %s)\n", domain,
|
|
|
|
|
rr_class, dns_type_to_string(rr_type));
|
|
|
|
|
}
|
|
|
|
|
if (retrans > 0)
|
|
|
|
|
{
|
|
|
|
|
save_retrans = _res.retrans;
|
|
|
|
|
_res.retrans = retrans;
|
|
|
|
|
}
|
|
|
|
|
if (retry > 0)
|
|
|
|
|
{
|
|
|
|
|
save_retry = _res.retry;
|
|
|
|
|
_res.retry = retry;
|
|
|
|
|
}
|
|
|
|
|
errno = 0;
|
|
|
|
|
SM_SET_H_ERRNO(0);
|
|
|
|
|
len = res_search(domain, rr_class, rr_type, reply, sizeof reply);
|
|
|
|
|
if (tTd(8, 16))
|
|
|
|
|
{
|
|
|
|
|
_res.options = old_options;
|
|
|
|
|
sm_dprintf("dns_lookup(%s, %d, %s) --> %d\n",
|
|
|
|
|
domain, rr_class, dns_type_to_string(rr_type), len);
|
|
|
|
|
}
|
|
|
|
|
if (len >= 0)
|
|
|
|
|
r = parse_dns_reply(reply, len);
|
|
|
|
|
if (retrans > 0)
|
|
|
|
|
_res.retrans = save_retrans;
|
|
|
|
|
if (retry > 0)
|
|
|
|
|
_res.retry = save_retry;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# if 0
|
|
|
|
|
DNS_REPLY_T *
|
|
|
|
|
dns_lookup(domain, type_name, retrans, retry)
|
|
|
|
|
const char *domain;
|
|
|
|
|
const char *type_name;
|
|
|
|
|
time_t retrans;
|
|
|
|
|
int retry;
|
|
|
|
|
{
|
|
|
|
|
int type;
|
|
|
|
|
|
|
|
|
|
type = dns_string_to_type(type_name);
|
|
|
|
|
if (type == -1)
|
|
|
|
|
{
|
|
|
|
|
if (tTd(8, 16))
|
|
|
|
|
sm_dprintf("dns_lookup: unknown resource type: `%s'\n",
|
|
|
|
|
type_name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return dns_lookup_int(domain, C_IN, type, retrans, retry);
|
|
|
|
|
}
|
|
|
|
|
# endif /* 0 */
|
|
|
|
|
# endif /* NAMED_BIND */
|
|
|
|
|
#endif /* DNSMAP */
|