resolve.c revision 55682
155682Smarkm/*
255682Smarkm * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#ifdef HAVE_CONFIG_H
3555682Smarkm#include <config.h>
3655682Smarkm#endif
3755682Smarkm#include "roken.h"
3855682Smarkm#ifdef HAVE_ARPA_NAMESER_H
3955682Smarkm#include <arpa/nameser.h>
4055682Smarkm#endif
4155682Smarkm#ifdef HAVE_RESOLV_H
4255682Smarkm#include <resolv.h>
4355682Smarkm#endif
4455682Smarkm#include "resolve.h"
4555682Smarkm
4655682SmarkmRCSID("$Id: resolve.c,v 1.22 1999/12/02 16:58:52 joda Exp $");
4755682Smarkm
4855682Smarkm#if defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND)
4955682Smarkm
5055682Smarkm#define DECL(X) {#X, T_##X}
5155682Smarkm
5255682Smarkmstatic struct stot{
5355682Smarkm    const char *name;
5455682Smarkm    int type;
5555682Smarkm}stot[] = {
5655682Smarkm    DECL(A),
5755682Smarkm    DECL(NS),
5855682Smarkm    DECL(CNAME),
5955682Smarkm    DECL(PTR),
6055682Smarkm    DECL(MX),
6155682Smarkm    DECL(TXT),
6255682Smarkm    DECL(AFSDB),
6355682Smarkm    DECL(SRV),
6455682Smarkm    {NULL, 	0}
6555682Smarkm};
6655682Smarkm
6755682Smarkmint _resolve_debug;
6855682Smarkm
6955682Smarkmstatic int
7055682Smarkmstring_to_type(const char *name)
7155682Smarkm{
7255682Smarkm    struct stot *p = stot;
7355682Smarkm    for(p = stot; p->name; p++)
7455682Smarkm	if(strcasecmp(name, p->name) == 0)
7555682Smarkm	    return p->type;
7655682Smarkm    return -1;
7755682Smarkm}
7855682Smarkm
7955682Smarkmstatic const char *
8055682Smarkmtype_to_string(int type)
8155682Smarkm{
8255682Smarkm    struct stot *p = stot;
8355682Smarkm    for(p = stot; p->name; p++)
8455682Smarkm	if(type == p->type)
8555682Smarkm	    return p->name;
8655682Smarkm    return NULL;
8755682Smarkm}
8855682Smarkm
8955682Smarkmvoid
9055682Smarkmdns_free_data(struct dns_reply *r)
9155682Smarkm{
9255682Smarkm    struct resource_record *rr;
9355682Smarkm    if(r->q.domain)
9455682Smarkm	free(r->q.domain);
9555682Smarkm    for(rr = r->head; rr;){
9655682Smarkm	struct resource_record *tmp = rr;
9755682Smarkm	if(rr->domain)
9855682Smarkm	    free(rr->domain);
9955682Smarkm	if(rr->u.data)
10055682Smarkm	    free(rr->u.data);
10155682Smarkm	rr = rr->next;
10255682Smarkm	free(tmp);
10355682Smarkm    }
10455682Smarkm    free (r);
10555682Smarkm}
10655682Smarkm
10755682Smarkmstatic struct dns_reply*
10855682Smarkmparse_reply(unsigned char *data, int len)
10955682Smarkm{
11055682Smarkm    unsigned char *p;
11155682Smarkm    char host[128];
11255682Smarkm    int status;
11355682Smarkm
11455682Smarkm    struct dns_reply *r;
11555682Smarkm    struct resource_record **rr;
11655682Smarkm
11755682Smarkm    r = calloc(1, sizeof(*r));
11855682Smarkm    if (r == NULL)
11955682Smarkm	return NULL;
12055682Smarkm
12155682Smarkm    p = data;
12255682Smarkm#if 0
12355682Smarkm    /* doesn't work on Crays */
12455682Smarkm    memcpy(&r->h, p, sizeof(HEADER));
12555682Smarkm    p += sizeof(HEADER);
12655682Smarkm#else
12755682Smarkm    memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
12855682Smarkm    p += 12;
12955682Smarkm#endif
13055682Smarkm    status = dn_expand(data, data + len, p, host, sizeof(host));
13155682Smarkm    if(status < 0){
13255682Smarkm	dns_free_data(r);
13355682Smarkm	return NULL;
13455682Smarkm    }
13555682Smarkm    r->q.domain = strdup(host);
13655682Smarkm    if(r->q.domain == NULL) {
13755682Smarkm	dns_free_data(r);
13855682Smarkm	return NULL;
13955682Smarkm    }
14055682Smarkm    p += status;
14155682Smarkm    r->q.type = (p[0] << 8 | p[1]);
14255682Smarkm    p += 2;
14355682Smarkm    r->q.class = (p[0] << 8 | p[1]);
14455682Smarkm    p += 2;
14555682Smarkm    rr = &r->head;
14655682Smarkm    while(p < data + len){
14755682Smarkm	int type, class, ttl, size;
14855682Smarkm	status = dn_expand(data, data + len, p, host, sizeof(host));
14955682Smarkm	if(status < 0){
15055682Smarkm	    dns_free_data(r);
15155682Smarkm	    return NULL;
15255682Smarkm	}
15355682Smarkm	p += status;
15455682Smarkm	type = (p[0] << 8) | p[1];
15555682Smarkm	p += 2;
15655682Smarkm	class = (p[0] << 8) | p[1];
15755682Smarkm	p += 2;
15855682Smarkm	ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
15955682Smarkm	p += 4;
16055682Smarkm	size = (p[0] << 8) | p[1];
16155682Smarkm	p += 2;
16255682Smarkm	*rr = (struct resource_record*)calloc(1,
16355682Smarkm					      sizeof(struct resource_record));
16455682Smarkm	if(*rr == NULL) {
16555682Smarkm	    dns_free_data(r);
16655682Smarkm	    return NULL;
16755682Smarkm	}
16855682Smarkm	(*rr)->domain = strdup(host);
16955682Smarkm	if((*rr)->domain == NULL) {
17055682Smarkm	    dns_free_data(r);
17155682Smarkm	    return NULL;
17255682Smarkm	}
17355682Smarkm	(*rr)->type = type;
17455682Smarkm	(*rr)->class = class;
17555682Smarkm	(*rr)->ttl = ttl;
17655682Smarkm	(*rr)->size = size;
17755682Smarkm	switch(type){
17855682Smarkm	case T_NS:
17955682Smarkm	case T_CNAME:
18055682Smarkm	case T_PTR:
18155682Smarkm	    status = dn_expand(data, data + len, p, host, sizeof(host));
18255682Smarkm	    if(status < 0){
18355682Smarkm		dns_free_data(r);
18455682Smarkm		return NULL;
18555682Smarkm	    }
18655682Smarkm	    (*rr)->u.txt = strdup(host);
18755682Smarkm	    if((*rr)->u.txt == NULL) {
18855682Smarkm		dns_free_data(r);
18955682Smarkm		return NULL;
19055682Smarkm	    }
19155682Smarkm	    break;
19255682Smarkm	case T_MX:
19355682Smarkm	case T_AFSDB:{
19455682Smarkm	    status = dn_expand(data, data + len, p + 2, host, sizeof(host));
19555682Smarkm	    if(status < 0){
19655682Smarkm		dns_free_data(r);
19755682Smarkm		return NULL;
19855682Smarkm	    }
19955682Smarkm	    (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
20055682Smarkm						    strlen(host));
20155682Smarkm	    if((*rr)->u.mx == NULL) {
20255682Smarkm		dns_free_data(r);
20355682Smarkm		return NULL;
20455682Smarkm	    }
20555682Smarkm	    (*rr)->u.mx->preference = (p[0] << 8) | p[1];
20655682Smarkm	    strcpy((*rr)->u.mx->domain, host);
20755682Smarkm	    break;
20855682Smarkm	}
20955682Smarkm	case T_SRV:{
21055682Smarkm	    status = dn_expand(data, data + len, p + 6, host, sizeof(host));
21155682Smarkm	    if(status < 0){
21255682Smarkm		dns_free_data(r);
21355682Smarkm		return NULL;
21455682Smarkm	    }
21555682Smarkm	    (*rr)->u.srv =
21655682Smarkm		(struct srv_record*)malloc(sizeof(struct srv_record) +
21755682Smarkm					   strlen(host));
21855682Smarkm	    if((*rr)->u.srv == NULL) {
21955682Smarkm		dns_free_data(r);
22055682Smarkm		return NULL;
22155682Smarkm	    }
22255682Smarkm	    (*rr)->u.srv->priority = (p[0] << 8) | p[1];
22355682Smarkm	    (*rr)->u.srv->weight = (p[2] << 8) | p[3];
22455682Smarkm	    (*rr)->u.srv->port = (p[4] << 8) | p[5];
22555682Smarkm	    strcpy((*rr)->u.srv->target, host);
22655682Smarkm	    break;
22755682Smarkm	}
22855682Smarkm	case T_TXT:{
22955682Smarkm	    (*rr)->u.txt = (char*)malloc(size + 1);
23055682Smarkm	    if((*rr)->u.txt == NULL) {
23155682Smarkm		dns_free_data(r);
23255682Smarkm		return NULL;
23355682Smarkm	    }
23455682Smarkm	    strncpy((*rr)->u.txt, (char*)p + 1, *p);
23555682Smarkm	    (*rr)->u.txt[*p] = 0;
23655682Smarkm	    break;
23755682Smarkm	}
23855682Smarkm
23955682Smarkm	default:
24055682Smarkm	    (*rr)->u.data = (unsigned char*)malloc(size);
24155682Smarkm	    if(size != 0 && (*rr)->u.data == NULL) {
24255682Smarkm		dns_free_data(r);
24355682Smarkm		return NULL;
24455682Smarkm	    }
24555682Smarkm	    memcpy((*rr)->u.data, p, size);
24655682Smarkm	}
24755682Smarkm	p += size;
24855682Smarkm	rr = &(*rr)->next;
24955682Smarkm    }
25055682Smarkm    *rr = NULL;
25155682Smarkm    return r;
25255682Smarkm}
25355682Smarkm
25455682Smarkmstatic struct dns_reply *
25555682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type)
25655682Smarkm{
25755682Smarkm    unsigned char reply[1024];
25855682Smarkm    int len;
25955682Smarkm    struct dns_reply *r = NULL;
26055682Smarkm    u_long old_options = 0;
26155682Smarkm
26255682Smarkm    if (_resolve_debug) {
26355682Smarkm        old_options = _res.options;
26455682Smarkm	_res.options |= RES_DEBUG;
26555682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
26655682Smarkm		rr_class, type_to_string(rr_type));
26755682Smarkm    }
26855682Smarkm    len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
26955682Smarkm    if (_resolve_debug) {
27055682Smarkm        _res.options = old_options;
27155682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
27255682Smarkm		domain, rr_class, type_to_string(rr_type), len);
27355682Smarkm    }
27455682Smarkm    if (len >= 0)
27555682Smarkm	r = parse_reply(reply, len);
27655682Smarkm    return r;
27755682Smarkm}
27855682Smarkm
27955682Smarkmstruct dns_reply *
28055682Smarkmdns_lookup(const char *domain, const char *type_name)
28155682Smarkm{
28255682Smarkm    int type;
28355682Smarkm
28455682Smarkm    type = string_to_type(type_name);
28555682Smarkm    if(type == -1) {
28655682Smarkm	if(_resolve_debug)
28755682Smarkm	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
28855682Smarkm		    type_name);
28955682Smarkm	return NULL;
29055682Smarkm    }
29155682Smarkm    return dns_lookup_int(domain, C_IN, type);
29255682Smarkm}
29355682Smarkm
29455682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
29555682Smarkm
29655682Smarkmstruct dns_reply *
29755682Smarkmdns_lookup(const char *domain, const char *type_name)
29855682Smarkm{
29955682Smarkm    return NULL;
30055682Smarkm}
30155682Smarkm
30255682Smarkmvoid
30355682Smarkmdns_free_data(struct dns_reply *r)
30455682Smarkm{
30555682Smarkm}
30655682Smarkm
30755682Smarkm#endif
30855682Smarkm
30955682Smarkm#ifdef TEST
31055682Smarkmint
31155682Smarkmmain(int argc, char **argv)
31255682Smarkm{
31355682Smarkm    struct dns_reply *r;
31455682Smarkm    struct resource_record *rr;
31555682Smarkm    r = dns_lookup(argv[1], argv[2]);
31655682Smarkm    if(r == NULL){
31755682Smarkm	printf("No reply.\n");
31855682Smarkm	return 1;
31955682Smarkm    }
32055682Smarkm    for(rr = r->head; rr;rr=rr->next){
32155682Smarkm	printf("%s %s %d ", rr->domain, type_to_string(rr->type), rr->ttl);
32255682Smarkm	switch(rr->type){
32355682Smarkm	case T_NS:
32455682Smarkm	    printf("%s\n", (char*)rr->u.data);
32555682Smarkm	    break;
32655682Smarkm	case T_A:
32755682Smarkm	    printf("%d.%d.%d.%d\n",
32855682Smarkm		   ((unsigned char*)rr->u.data)[0],
32955682Smarkm		   ((unsigned char*)rr->u.data)[1],
33055682Smarkm		   ((unsigned char*)rr->u.data)[2],
33155682Smarkm		   ((unsigned char*)rr->u.data)[3]);
33255682Smarkm	    break;
33355682Smarkm	case T_MX:
33455682Smarkm	case T_AFSDB:{
33555682Smarkm	    struct mx_record *mx = (struct mx_record*)rr->u.data;
33655682Smarkm	    printf("%d %s\n", mx->preference, mx->domain);
33755682Smarkm	    break;
33855682Smarkm	}
33955682Smarkm	case T_SRV:{
34055682Smarkm	    struct srv_record *srv = (struct srv_record*)rr->u.data;
34155682Smarkm	    printf("%d %d %d %s\n", srv->priority, srv->weight,
34255682Smarkm		   srv->port, srv->target);
34355682Smarkm	    break;
34455682Smarkm	}
34555682Smarkm	default:
34655682Smarkm	    printf("\n");
34755682Smarkm	    break;
34855682Smarkm	}
34955682Smarkm    }
35055682Smarkm
35155682Smarkm    return 0;
35255682Smarkm}
35355682Smarkm#endif
354