resolve.c revision 72445
155682Smarkm/*
272445Sassar * Copyright (c) 1995 - 2000 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
4672445SassarRCSID("$Id: resolve.c,v 1.26 2000/06/27 01:15:53 assar 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),
5972445Sassar    DECL(SOA),
6055682Smarkm    DECL(PTR),
6155682Smarkm    DECL(MX),
6255682Smarkm    DECL(TXT),
6355682Smarkm    DECL(AFSDB),
6472445Sassar    DECL(SIG),
6572445Sassar    DECL(KEY),
6655682Smarkm    DECL(SRV),
6772445Sassar    DECL(NAPTR),
6855682Smarkm    {NULL, 	0}
6955682Smarkm};
7055682Smarkm
7172445Sassarint _resolve_debug = 0;
7255682Smarkm
7372445Sassarint
7472445Sassardns_string_to_type(const char *name)
7555682Smarkm{
7655682Smarkm    struct stot *p = stot;
7755682Smarkm    for(p = stot; p->name; p++)
7855682Smarkm	if(strcasecmp(name, p->name) == 0)
7955682Smarkm	    return p->type;
8055682Smarkm    return -1;
8155682Smarkm}
8255682Smarkm
8372445Sassarconst char *
8472445Sassardns_type_to_string(int type)
8555682Smarkm{
8655682Smarkm    struct stot *p = stot;
8755682Smarkm    for(p = stot; p->name; p++)
8855682Smarkm	if(type == p->type)
8955682Smarkm	    return p->name;
9055682Smarkm    return NULL;
9155682Smarkm}
9255682Smarkm
9355682Smarkmvoid
9455682Smarkmdns_free_data(struct dns_reply *r)
9555682Smarkm{
9655682Smarkm    struct resource_record *rr;
9755682Smarkm    if(r->q.domain)
9855682Smarkm	free(r->q.domain);
9955682Smarkm    for(rr = r->head; rr;){
10055682Smarkm	struct resource_record *tmp = rr;
10155682Smarkm	if(rr->domain)
10255682Smarkm	    free(rr->domain);
10355682Smarkm	if(rr->u.data)
10455682Smarkm	    free(rr->u.data);
10555682Smarkm	rr = rr->next;
10655682Smarkm	free(tmp);
10755682Smarkm    }
10855682Smarkm    free (r);
10955682Smarkm}
11055682Smarkm
11155682Smarkmstatic struct dns_reply*
11255682Smarkmparse_reply(unsigned char *data, int len)
11355682Smarkm{
11455682Smarkm    unsigned char *p;
11555682Smarkm    char host[128];
11655682Smarkm    int status;
11755682Smarkm
11855682Smarkm    struct dns_reply *r;
11955682Smarkm    struct resource_record **rr;
12055682Smarkm
12155682Smarkm    r = calloc(1, sizeof(*r));
12255682Smarkm    if (r == NULL)
12355682Smarkm	return NULL;
12455682Smarkm
12555682Smarkm    p = data;
12655682Smarkm#if 0
12755682Smarkm    /* doesn't work on Crays */
12855682Smarkm    memcpy(&r->h, p, sizeof(HEADER));
12955682Smarkm    p += sizeof(HEADER);
13055682Smarkm#else
13155682Smarkm    memcpy(&r->h, p, 12); /* XXX this will probably be mostly garbage */
13255682Smarkm    p += 12;
13355682Smarkm#endif
13455682Smarkm    status = dn_expand(data, data + len, p, host, sizeof(host));
13555682Smarkm    if(status < 0){
13655682Smarkm	dns_free_data(r);
13755682Smarkm	return NULL;
13855682Smarkm    }
13955682Smarkm    r->q.domain = strdup(host);
14055682Smarkm    if(r->q.domain == NULL) {
14155682Smarkm	dns_free_data(r);
14255682Smarkm	return NULL;
14355682Smarkm    }
14455682Smarkm    p += status;
14555682Smarkm    r->q.type = (p[0] << 8 | p[1]);
14655682Smarkm    p += 2;
14755682Smarkm    r->q.class = (p[0] << 8 | p[1]);
14855682Smarkm    p += 2;
14955682Smarkm    rr = &r->head;
15055682Smarkm    while(p < data + len){
15155682Smarkm	int type, class, ttl, size;
15255682Smarkm	status = dn_expand(data, data + len, p, host, sizeof(host));
15355682Smarkm	if(status < 0){
15455682Smarkm	    dns_free_data(r);
15555682Smarkm	    return NULL;
15655682Smarkm	}
15755682Smarkm	p += status;
15855682Smarkm	type = (p[0] << 8) | p[1];
15955682Smarkm	p += 2;
16055682Smarkm	class = (p[0] << 8) | p[1];
16155682Smarkm	p += 2;
16255682Smarkm	ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
16355682Smarkm	p += 4;
16455682Smarkm	size = (p[0] << 8) | p[1];
16555682Smarkm	p += 2;
16655682Smarkm	*rr = (struct resource_record*)calloc(1,
16755682Smarkm					      sizeof(struct resource_record));
16855682Smarkm	if(*rr == NULL) {
16955682Smarkm	    dns_free_data(r);
17055682Smarkm	    return NULL;
17155682Smarkm	}
17255682Smarkm	(*rr)->domain = strdup(host);
17355682Smarkm	if((*rr)->domain == NULL) {
17455682Smarkm	    dns_free_data(r);
17555682Smarkm	    return NULL;
17655682Smarkm	}
17755682Smarkm	(*rr)->type = type;
17855682Smarkm	(*rr)->class = class;
17955682Smarkm	(*rr)->ttl = ttl;
18055682Smarkm	(*rr)->size = size;
18155682Smarkm	switch(type){
18255682Smarkm	case T_NS:
18355682Smarkm	case T_CNAME:
18455682Smarkm	case T_PTR:
18555682Smarkm	    status = dn_expand(data, data + len, p, host, sizeof(host));
18655682Smarkm	    if(status < 0){
18755682Smarkm		dns_free_data(r);
18855682Smarkm		return NULL;
18955682Smarkm	    }
19055682Smarkm	    (*rr)->u.txt = strdup(host);
19155682Smarkm	    if((*rr)->u.txt == NULL) {
19255682Smarkm		dns_free_data(r);
19355682Smarkm		return NULL;
19455682Smarkm	    }
19555682Smarkm	    break;
19655682Smarkm	case T_MX:
19755682Smarkm	case T_AFSDB:{
19855682Smarkm	    status = dn_expand(data, data + len, p + 2, host, sizeof(host));
19955682Smarkm	    if(status < 0){
20055682Smarkm		dns_free_data(r);
20155682Smarkm		return NULL;
20255682Smarkm	    }
20355682Smarkm	    (*rr)->u.mx = (struct mx_record*)malloc(sizeof(struct mx_record) +
20455682Smarkm						    strlen(host));
20555682Smarkm	    if((*rr)->u.mx == NULL) {
20655682Smarkm		dns_free_data(r);
20755682Smarkm		return NULL;
20855682Smarkm	    }
20955682Smarkm	    (*rr)->u.mx->preference = (p[0] << 8) | p[1];
21055682Smarkm	    strcpy((*rr)->u.mx->domain, host);
21155682Smarkm	    break;
21255682Smarkm	}
21355682Smarkm	case T_SRV:{
21455682Smarkm	    status = dn_expand(data, data + len, p + 6, host, sizeof(host));
21555682Smarkm	    if(status < 0){
21655682Smarkm		dns_free_data(r);
21755682Smarkm		return NULL;
21855682Smarkm	    }
21955682Smarkm	    (*rr)->u.srv =
22055682Smarkm		(struct srv_record*)malloc(sizeof(struct srv_record) +
22155682Smarkm					   strlen(host));
22255682Smarkm	    if((*rr)->u.srv == NULL) {
22355682Smarkm		dns_free_data(r);
22455682Smarkm		return NULL;
22555682Smarkm	    }
22655682Smarkm	    (*rr)->u.srv->priority = (p[0] << 8) | p[1];
22755682Smarkm	    (*rr)->u.srv->weight = (p[2] << 8) | p[3];
22855682Smarkm	    (*rr)->u.srv->port = (p[4] << 8) | p[5];
22955682Smarkm	    strcpy((*rr)->u.srv->target, host);
23055682Smarkm	    break;
23155682Smarkm	}
23255682Smarkm	case T_TXT:{
23355682Smarkm	    (*rr)->u.txt = (char*)malloc(size + 1);
23455682Smarkm	    if((*rr)->u.txt == NULL) {
23555682Smarkm		dns_free_data(r);
23655682Smarkm		return NULL;
23755682Smarkm	    }
23855682Smarkm	    strncpy((*rr)->u.txt, (char*)p + 1, *p);
23955682Smarkm	    (*rr)->u.txt[*p] = 0;
24055682Smarkm	    break;
24155682Smarkm	}
24272445Sassar	case T_KEY : {
24372445Sassar	    size_t key_len;
24472445Sassar
24572445Sassar	    key_len = size - 4;
24672445Sassar	    (*rr)->u.key = malloc (sizeof(*(*rr)->u.key) + key_len - 1);
24772445Sassar	    if ((*rr)->u.key == NULL) {
24872445Sassar		dns_free_data (r);
24972445Sassar		return NULL;
25072445Sassar	    }
25172445Sassar
25272445Sassar	    (*rr)->u.key->flags     = (p[0] << 8) | p[1];
25372445Sassar	    (*rr)->u.key->protocol  = p[2];
25472445Sassar	    (*rr)->u.key->algorithm = p[3];
25572445Sassar	    (*rr)->u.key->key_len   = key_len;
25672445Sassar	    memcpy ((*rr)->u.key->key_data, p + 4, key_len);
25772445Sassar	    break;
25872445Sassar	}
25972445Sassar	case T_SIG : {
26072445Sassar	    size_t sig_len;
26172445Sassar
26272445Sassar	    status = dn_expand (data, data + len, p + 18, host, sizeof(host));
26372445Sassar	    if (status < 0) {
26472445Sassar		dns_free_data (r);
26572445Sassar		return NULL;
26672445Sassar	    }
26772445Sassar	    sig_len = len - 18 - status;
26872445Sassar	    (*rr)->u.sig = malloc(sizeof(*(*rr)->u.sig)
26972445Sassar				  + strlen(host) + sig_len);
27072445Sassar	    if ((*rr)->u.sig == NULL) {
27172445Sassar		dns_free_data (r);
27272445Sassar		return NULL;
27372445Sassar	    }
27472445Sassar	    (*rr)->u.sig->type           = (p[0] << 8) | p[1];
27572445Sassar	    (*rr)->u.sig->algorithm      = p[2];
27672445Sassar	    (*rr)->u.sig->labels         = p[3];
27772445Sassar	    (*rr)->u.sig->orig_ttl       = (p[4] << 24) | (p[5] << 16)
27872445Sassar		| (p[6] << 8) | p[7];
27972445Sassar	    (*rr)->u.sig->sig_expiration = (p[8] << 24) | (p[9] << 16)
28072445Sassar		| (p[10] << 8) | p[11];
28172445Sassar	    (*rr)->u.sig->sig_inception  = (p[12] << 24) | (p[13] << 16)
28272445Sassar		| (p[14] << 8) | p[15];
28372445Sassar	    (*rr)->u.sig->key_tag        = (p[16] << 8) | p[17];
28472445Sassar	    (*rr)->u.sig->sig_len        = sig_len;
28572445Sassar	    memcpy ((*rr)->u.sig->sig_data, p + 18 + status, sig_len);
28672445Sassar	    (*rr)->u.sig->signer         = &(*rr)->u.sig->sig_data[sig_len];
28772445Sassar	    strcpy((*rr)->u.sig->signer, host);
28872445Sassar	    break;
28972445Sassar	}
29072445Sassar
29172445Sassar	case T_CERT : {
29272445Sassar	    size_t cert_len;
29372445Sassar
29472445Sassar	    cert_len = size - 5;
29572445Sassar	    (*rr)->u.cert = malloc (sizeof(*(*rr)->u.cert) + cert_len - 1);
29672445Sassar	    if ((*rr)->u.cert == NULL) {
29772445Sassar		dns_free_data (r);
29872445Sassar		return NULL;
29972445Sassar	    }
30072445Sassar
30172445Sassar	    (*rr)->u.cert->type      = (p[0] << 8) | p[1];
30272445Sassar	    (*rr)->u.cert->tag       = (p[2] << 8) | p[3];
30372445Sassar	    (*rr)->u.cert->algorithm = p[4];
30472445Sassar	    (*rr)->u.cert->cert_len  = cert_len;
30572445Sassar	    memcpy ((*rr)->u.cert->cert_data, p + 5, cert_len);
30672445Sassar	    break;
30772445Sassar	}
30855682Smarkm	default:
30955682Smarkm	    (*rr)->u.data = (unsigned char*)malloc(size);
31055682Smarkm	    if(size != 0 && (*rr)->u.data == NULL) {
31155682Smarkm		dns_free_data(r);
31255682Smarkm		return NULL;
31355682Smarkm	    }
31455682Smarkm	    memcpy((*rr)->u.data, p, size);
31555682Smarkm	}
31655682Smarkm	p += size;
31755682Smarkm	rr = &(*rr)->next;
31855682Smarkm    }
31955682Smarkm    *rr = NULL;
32055682Smarkm    return r;
32155682Smarkm}
32255682Smarkm
32355682Smarkmstatic struct dns_reply *
32455682Smarkmdns_lookup_int(const char *domain, int rr_class, int rr_type)
32555682Smarkm{
32655682Smarkm    unsigned char reply[1024];
32755682Smarkm    int len;
32855682Smarkm    struct dns_reply *r = NULL;
32955682Smarkm    u_long old_options = 0;
33055682Smarkm
33155682Smarkm    if (_resolve_debug) {
33255682Smarkm        old_options = _res.options;
33355682Smarkm	_res.options |= RES_DEBUG;
33455682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s)\n", domain,
33572445Sassar		rr_class, dns_type_to_string(rr_type));
33655682Smarkm    }
33755682Smarkm    len = res_search(domain, rr_class, rr_type, reply, sizeof(reply));
33855682Smarkm    if (_resolve_debug) {
33955682Smarkm        _res.options = old_options;
34055682Smarkm	fprintf(stderr, "dns_lookup(%s, %d, %s) --> %d\n",
34172445Sassar		domain, rr_class, dns_type_to_string(rr_type), len);
34255682Smarkm    }
34355682Smarkm    if (len >= 0)
34455682Smarkm	r = parse_reply(reply, len);
34555682Smarkm    return r;
34655682Smarkm}
34755682Smarkm
34855682Smarkmstruct dns_reply *
34955682Smarkmdns_lookup(const char *domain, const char *type_name)
35055682Smarkm{
35155682Smarkm    int type;
35255682Smarkm
35372445Sassar    type = dns_string_to_type(type_name);
35455682Smarkm    if(type == -1) {
35555682Smarkm	if(_resolve_debug)
35655682Smarkm	    fprintf(stderr, "dns_lookup: unknown resource type: `%s'\n",
35755682Smarkm		    type_name);
35855682Smarkm	return NULL;
35955682Smarkm    }
36055682Smarkm    return dns_lookup_int(domain, C_IN, type);
36155682Smarkm}
36255682Smarkm
36355682Smarkm#else /* NOT defined(HAVE_RES_SEARCH) && defined(HAVE_DN_EXPAND) */
36455682Smarkm
36555682Smarkmstruct dns_reply *
36655682Smarkmdns_lookup(const char *domain, const char *type_name)
36755682Smarkm{
36855682Smarkm    return NULL;
36955682Smarkm}
37055682Smarkm
37155682Smarkmvoid
37255682Smarkmdns_free_data(struct dns_reply *r)
37355682Smarkm{
37455682Smarkm}
37555682Smarkm
37655682Smarkm#endif
37755682Smarkm
37855682Smarkm#ifdef TEST
37955682Smarkmint
38055682Smarkmmain(int argc, char **argv)
38155682Smarkm{
38255682Smarkm    struct dns_reply *r;
38355682Smarkm    struct resource_record *rr;
38455682Smarkm    r = dns_lookup(argv[1], argv[2]);
38555682Smarkm    if(r == NULL){
38655682Smarkm	printf("No reply.\n");
38755682Smarkm	return 1;
38855682Smarkm    }
38955682Smarkm    for(rr = r->head; rr;rr=rr->next){
39072445Sassar	printf("%s %s %d ", rr->domain, dns_type_to_string(rr->type), rr->ttl);
39155682Smarkm	switch(rr->type){
39255682Smarkm	case T_NS:
39372445Sassar	case T_CNAME:
39472445Sassar	case T_PTR:
39555682Smarkm	    printf("%s\n", (char*)rr->u.data);
39655682Smarkm	    break;
39755682Smarkm	case T_A:
39872445Sassar	    printf("%s\n", inet_ntoa(*rr->u.a));
39955682Smarkm	    break;
40055682Smarkm	case T_MX:
40155682Smarkm	case T_AFSDB:{
40272445Sassar	    printf("%d %s\n", rr->u.mx->preference, rr->u.mx->domain);
40355682Smarkm	    break;
40455682Smarkm	}
40555682Smarkm	case T_SRV:{
40672445Sassar	    struct srv_record *srv = rr->u.srv;
40755682Smarkm	    printf("%d %d %d %s\n", srv->priority, srv->weight,
40855682Smarkm		   srv->port, srv->target);
40955682Smarkm	    break;
41055682Smarkm	}
41172445Sassar	case T_TXT: {
41272445Sassar	    printf("%s\n", rr->u.txt);
41372445Sassar	    break;
41472445Sassar	}
41572445Sassar	case T_SIG : {
41672445Sassar	    struct sig_record *sig = rr->u.sig;
41772445Sassar	    const char *type_string = dns_type_to_string (sig->type);
41872445Sassar
41972445Sassar	    printf ("type %u (%s), algorithm %u, labels %u, orig_ttl %u, sig_expiration %u, sig_inception %u, key_tag %u, signer %s\n",
42072445Sassar		    sig->type, type_string ? type_string : "",
42172445Sassar		    sig->algorithm, sig->labels, sig->orig_ttl,
42272445Sassar		    sig->sig_expiration, sig->sig_inception, sig->key_tag,
42372445Sassar		    sig->signer);
42472445Sassar	    break;
42572445Sassar	}
42672445Sassar	case T_KEY : {
42772445Sassar	    struct key_record *key = rr->u.key;
42872445Sassar
42972445Sassar	    printf ("flags %u, protocol %u, algorithm %u\n",
43072445Sassar		    key->flags, key->protocol, key->algorithm);
43172445Sassar	    break;
43272445Sassar	}
43355682Smarkm	default:
43455682Smarkm	    printf("\n");
43555682Smarkm	    break;
43655682Smarkm	}
43755682Smarkm    }
43855682Smarkm
43955682Smarkm    return 0;
44055682Smarkm}
44155682Smarkm#endif
442