Пример #1
0
/**
 * @return 成功した場合は NETDB_SUCCESS.
 */
static int
DnsResolver_lookupTxtData(DnsResolver *self, int rrtype, const char *domain, DnsTxtResponse **resp)
{
    int query_stat = DnsResolver_query(self, domain, rrtype);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsTxtResponse *respobj =
        (DnsTxtResponse *) malloc(sizeof(DnsTxtResponse) + msg_count * sizeof(char *));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsTxtResponse) + msg_count * sizeof(char *));
    respobj->num = 0;
    for (size_t n = 0; n < msg_count; ++n) {
        ns_rr rr;
        int parse_stat = ns_parserr(&self->msghanlde, ns_s_an, n, &rr);
        if (0 != parse_stat) {
            goto formerr;
        }   // end if
        if (ns_t_txt != ns_rr_type(rr)) {
            continue;
        }   // end if
        respobj->data[respobj->num] = (char *) malloc(ns_rr_rdlen(rr)); // RDLEN を越えることはない.
        if (NULL == respobj->data[respobj->num]) {
            goto noresource;
        }   // end if
        const unsigned char *rdata = ns_rr_rdata(rr);
        const unsigned char *rdata_tail = ns_rr_rdata(rr) + ns_rr_rdlen(rr);
        char *bufp = respobj->data[respobj->num];
        while (rdata < rdata_tail) {
            // 長さフィールドが RDLEN の中に収まっているか確認する
            if (rdata_tail < rdata + (*rdata) + 1) {
                free(respobj->data[respobj->num]);
                goto formerr;
            }   // end if
            memcpy(bufp, rdata + 1, *rdata);
            bufp += (size_t) *rdata;
            rdata += (size_t) *rdata + 1;
        }   // end while
        *bufp = '\0';   // 扱いやすいように NULL 終端させる
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

  formerr:
    DnsTxtResponse_free(respobj);
    return DnsResolver_setError(self, NO_RECOVERY);

  noresource:
    DnsTxtResponse_free(respobj);
    return DnsResolver_setError(self, NETDB_INTERNAL);
}   // end function : DnsResolver_lookupTxtData
Пример #2
0
static void
parse_answer_section(ns_msg *msg) {
	int rrnum, rrmax;
	ns_rr rr;
	uint16_t prio, weight, port, len;
	const unsigned char *rdata;
	char *tname;

	rrmax = ns_msg_count(*msg, ns_s_an);
	for (rrnum = 0; rrnum < rrmax; rrnum++) {
		if (ns_parserr(msg, ns_s_an, rrnum, &rr)) {
			perror("ns_parserr");
			exit(EXIT_FAILURE);
		}
		if (ns_rr_type(rr) == ns_t_srv) {
			len = ns_rr_rdlen(rr);
			rdata = ns_rr_rdata(rr);
			if (len > 3U * NS_INT16SZ) {
				NS_GET16(prio, rdata);
				NS_GET16(weight, rdata);
				NS_GET16(port, rdata);
				len -= 3U * NS_INT16SZ;
				tname = target_name(rdata);
				insert_tuple(tname, prio, weight, port);
			}
		}
	}
}
Пример #3
0
static int
app_parse_txt(radiodns_app_t *app, ns_msg handle, ns_rr rr, char *dnbuf)
{
	const unsigned char *p, *start;
	unsigned char l;
	int rrlen;

	(void) handle;

	p = start = ns_rr_rdata(rr);
	rrlen = ns_rr_rdlen(rr);
	while(p < start + rrlen)
	{
		l = *p;					
		p++;
		if(p + l > start + rrlen)
		{
			break;
		}
		memcpy(dnbuf, p, l);
		dnbuf[l] = 0;
		app_parse_params(app, dnbuf);
		p += l;
	}
	return 0;
}
Пример #4
0
/*%
 *  Convert an RR to presentation format.
 *
 * return:
 *\li   Number of characters written to buf, or -1 (check errno).
 */
int
ns_sprintrr(const ns_msg* handle, const ns_rr* rr,
            const char* name_ctx, const char* origin,
            char* buf, size_t buflen) {
    int n;
    n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
                     ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
                     ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
                     name_ctx, origin, buf, buflen);
    return (n);
}
Пример #5
0
static JSBool parse_t_a(JSContext *cx, JSObject *robj, const ns_msg *hdl, const ns_rr *rr)
{
	char addr[16];
	JSString *str;

	if (ns_rr_rdlen(*rr) != 4)
		return JS_TRUE;

	if (!inet_ntop(AF_INET, ns_rr_rdata(*rr), addr, sizeof(addr)))
		return JS_TRUE;

	str = JS_NewStringCopyZ(cx, addr);
	if (!str)
		return JS_RetErrno(cx, ENOMEM);

	if (!JS_DefineProperty(cx, robj, "data", STRING_TO_JSVAL(str), NULL, NULL, JSPROP_ENUMERATE))
		return JS_RetErrno(cx, ENOMEM);

	return JS_TRUE;
}
Пример #6
0
int
DnsResolver_lookupAaaa(DnsResolver *self, const char *domain, DnsAaaaResponse **resp)
{
    int query_stat = DnsResolver_query(self, domain, ns_t_aaaa);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsAaaaResponse *respobj =
        (DnsAaaaResponse *) malloc(sizeof(DnsAaaaResponse) + msg_count * sizeof(struct in6_addr));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsAaaaResponse) + msg_count * sizeof(struct in6_addr));
    respobj->num = 0;
    for (size_t n = 0; n < msg_count; ++n) {
        ns_rr rr;
        int parse_stat = ns_parserr(&self->msghanlde, ns_s_an, n, &rr);
        if (0 != parse_stat) {
            goto formerr;
        }   // end if
        if (ns_t_aaaa != ns_rr_type(rr)) {
            continue;
        }   // end if
        if (NS_IN6ADDRSZ != ns_rr_rdlen(rr)) {
            goto formerr;
        }   // end if
        memcpy(&(respobj->addr[respobj->num]), ns_rr_rdata(rr), NS_IN6ADDRSZ);
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

  formerr:
    DnsAaaaResponse_free(respobj);
    return DnsResolver_setError(self, NO_RECOVERY);
}   // end function : DnsResolver_lookupAaaa
Пример #7
0
/*
 * krb5int_dns_nextans - get next matching answer record
 *
 * Sets pp to NULL if no more records.  Returns -1 on error, 0 on
 * success.
 */
int
krb5int_dns_nextans(struct krb5int_dns_state *ds,
                    const unsigned char **pp, int *lenp)
{
    int len;
    ns_rr rr;

    *pp = NULL;
    *lenp = 0;
    while (ds->cur_ans < ns_msg_count(ds->msg, ns_s_an)) {
        len = ns_parserr(&ds->msg, ns_s_an, ds->cur_ans, &rr);
        if (len < 0)
            return -1;
        ds->cur_ans++;
        if (ds->nclass == (int)ns_rr_class(rr)
            && ds->ntype == (int)ns_rr_type(rr)) {
            *pp = ns_rr_rdata(rr);
            *lenp = ns_rr_rdlen(rr);
            return 0;
        }
    }
    return 0;
}
Пример #8
0
/* Initialize a "newmsg" object by copying an existing parsed message.
 */
int
ns_newmsg_copy(ns_newmsg *handle, ns_msg *msg) {
    ns_flag flag;
    ns_sect sect;

    ns_newmsg_id(handle, ns_msg_id(*msg));
    for (flag = ns_f_qr; flag < ns_f_max; flag++)
        ns_newmsg_flag(handle, flag, ns_msg_getflag(*msg, flag));
    for (sect = ns_s_qd; sect < ns_s_max; sect++) {
        int i, count;

        count = ns_msg_count(*msg, sect);
        for (i = 0; i < count; i++) {
            ns_rr2 rr;
            int x;

            if (ns_parserr2(msg, sect, i, &rr) < 0)
                return (-1);
            if (sect == ns_s_qd)
                x = ns_newmsg_q(handle,
                                ns_rr_nname(rr),
                                ns_rr_type(rr),
                                ns_rr_class(rr));
            else
                x = ns_newmsg_rr(handle, sect,
                                 ns_rr_nname(rr),
                                 ns_rr_type(rr),
                                 ns_rr_class(rr),
                                 ns_rr_ttl(rr),
                                 ns_rr_rdlen(rr),
                                 ns_rr_rdata(rr));
            if (x < 0)
                return (-1);
        }
    }
    return (0);
}
Пример #9
0
static void
do_section(const res_state statp,
	   ns_msg *handle, ns_sect section,
	   int pflag, FILE *file)
{
	int n, sflag, rrnum;
	static int buflen = 2048;
	char *buf;
	ns_opcode opcode;
	ns_rr rr;

	/*
	 * Print answer records.
	 */
	sflag = (statp->pfcode & pflag);
	if (statp->pfcode && !sflag)
		return;

	buf = malloc(buflen);
	if (buf == NULL) {
		fprintf(file, ";; memory allocation failure\n");
		return;
	}

	opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
	rrnum = 0;
	for (;;) {
		if (ns_parserr(handle, section, rrnum, &rr)) {
			if (errno != ENODEV)
				fprintf(file, ";; ns_parserr: %s\n",
					strerror(errno));
			else if (rrnum > 0 && sflag != 0 &&
				 (statp->pfcode & RES_PRF_HEAD1))
				putc('\n', file);
			goto cleanup;
		}
		if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
			fprintf(file, ";; %s SECTION:\n",
				p_section(section, opcode));
		if (section == ns_s_qd)
			fprintf(file, ";;\t%s, type = %s, class = %s\n",
				ns_rr_name(rr),
				p_type(ns_rr_type(rr)),
				p_class(ns_rr_class(rr)));
		else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
			u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr);
			u_int32_t ttl = ns_rr_ttl(rr);

			fprintf(file,
				"; EDNS: version: %u, udp=%u, flags=%04x\n",
				(ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);

			while (rdatalen >= 4) {
				const u_char *cp = ns_rr_rdata(rr);
				int i;

				GETSHORT(optcode, cp);
				GETSHORT(optlen, cp);

				if (optcode == NS_OPT_NSID) {
					fputs("; NSID: ", file);
					if (optlen == 0) {
						fputs("; NSID\n", file);
					} else {
						fputs("; NSID: ", file);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%02x ",
								cp[i]);
						fputs(" (",file);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%c",
								isprint(cp[i])?
								cp[i] : '.');
						fputs(")\n", file);
					}
				} else {
					if (optlen == 0) {
						fprintf(file, "; OPT=%u\n",
							optcode);
					} else {
						fprintf(file, "; OPT=%u: ",
							optcode);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%02x ",
								cp[i]);
						fputs(" (",file);
						for (i = 0; i < optlen; i++)
							fprintf(file, "%c",
								isprint(cp[i]) ?
									cp[i] : '.');
						fputs(")\n", file);
					}
				}
				rdatalen -= 4 + optlen;
			}
		} else {
Пример #10
0
int
DnsResolver_lookupPtr(DnsResolver *self, int af, const void *addr, DnsPtrResponse **resp)
{
    // IPv6 の逆引きエントリ名生成に十分な長さのバッファを確保する.
    char domain[DNS_IP6_REVENT_MAXLEN];
    switch (af) {
    case AF_INET:
        if (!DnsResolver_expandReverseEntry4(addr, domain, sizeof(domain))) {
            abort();
        }   // end if
        break;
    case AF_INET6:
        if (!DnsResolver_expandReverseEntry6(addr, domain, sizeof(domain))) {
            abort();
        }   // end if
        break;
    default:
        errno = EAFNOSUPPORT;
        return NETDB_INTERNAL;
    }   // end if

    int query_stat = DnsResolver_query(self, domain, ns_t_ptr);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsPtrResponse *respobj =
        (DnsPtrResponse *) malloc(sizeof(DnsPtrResponse) + msg_count * sizeof(char *));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsPtrResponse) + msg_count * sizeof(char *));
    respobj->num = 0;
    for (size_t n = 0; n < msg_count; ++n) {
        ns_rr rr;
        int parse_stat = ns_parserr(&self->msghanlde, ns_s_an, n, &rr);
        if (0 != parse_stat) {
            goto formerr;
        }   // end if
        if (ns_t_ptr != ns_rr_type(rr)) {
            continue;
        }   // end if
        // NOTE: NS_MAXDNAME で十分なのかイマイチ確証が持てないが, bind8 の dig コマンドの実装でもこの値を使っていたのでいいのではないか.
        char dnamebuf[NS_MAXDNAME];
        int dnamelen =
            ns_name_uncompress(self->msgbuf, self->msgbuf + self->msglen, ns_rr_rdata(rr), dnamebuf,
                               sizeof(dnamebuf));
        if (dnamelen != ns_rr_rdlen(rr)) {
            goto formerr;
        }   // end if
        respobj->domain[respobj->num] = strdup(dnamebuf);
        if (NULL == respobj->domain[respobj->num]) {
            goto noresource;
        }   // end if
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

  formerr:
    DnsPtrResponse_free(respobj);
    return DnsResolver_setError(self, NO_RECOVERY);

  noresource:
    DnsPtrResponse_free(respobj);
    return DnsResolver_setError(self, NETDB_INTERNAL);
}   // end function : DnsResolver_lookupPtr
Пример #11
0
int srv_getaddrinfo(const char *node, const char *service,
		    const struct addrinfo *hints,
		    struct addrinfo **res)
{
    char *srv_name;
    size_t srv_name_size;
    char tgt_port[6];
#ifdef WIN32
    PDNS_RECORD resp, entry;
    char *tgt_name;
#else
    char tgt_name[BINKD_FQDNLEN + 1];
    unsigned char resp[SRVGAI_DNSRESPLEN];
    ns_msg nsb;
    ns_rr rrb;
    int rlen, i, rrlen;
    const unsigned char *p;
    struct in_addr dummy_addr;
#endif
    int rc;
    struct addrinfo *ai, **ai_last = res;

    /* we need sensible information for all parameters */
    if (!node || (node && !*node) || !service || (service && !*service) ||
	    !hints || !res)
	return getaddrinfo(node, service, hints, res);

    /* only domain names are supported */
    if (hints->ai_flags & AI_NUMERICHOST)
	return getaddrinfo(node, service, hints, res);

    /* detect IP addresses */
    if ((hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC) && 
#ifdef WIN32
	    inet_addr(node) != INADDR_NONE
#else
	    inet_aton(node, &dummy_addr) != 0
#endif
	    )
	return getaddrinfo(node, service, hints, res);
#ifdef AF_INET6
    if ((hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC) && 
	    strchr(node, ':'))
	return getaddrinfo(node, service, hints, res);
#endif

    /* only named services are supported */
    if ((hints->ai_flags & AI_NUMERICSERV) || *service == '0' ||
	    atoi(service) > 0)
	return getaddrinfo(node, service, hints, res);

    /* only TCP and UDP are supported */
    if (hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM)
	return getaddrinfo(node, service, hints, res);

    /*              _ <service>           ._  tcp . <node>           \0 */
    srv_name_size = 1 + strlen(service) + 2 + 3 + 1 + strlen(node) + 1;
    srv_name = malloc(srv_name_size);
    if (!srv_name)
	return EAI_MEMORY;

    /* construct domain name for SRV query */
    snprintf(srv_name, srv_name_size, "_%s._%s.%s", service,
	    hints->ai_socktype == SOCK_STREAM ? "tcp" : "udp", node);

#ifdef WIN32
    rc = DnsQuery(srv_name, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &resp, NULL);
#else
    rlen = res_search(srv_name, ns_c_in, ns_t_srv, resp, sizeof(resp));
#endif
    free(srv_name);

    /* fallback if DNS query does not return a single entry */
#ifdef WIN32
    if (rc != ERROR_SUCCESS)
#else
    if (rlen < 1)
#endif
	return getaddrinfo(node, service, hints, res);

#ifndef WIN32
    /* fallback in case we cannot parse the response */
    if (ns_initparse(resp, rlen, &nsb) < 0)
	return getaddrinfo(node, service, hints, res);
#endif

    /* iterate through result set -- might be incomplete */
#ifdef WIN32
    for (entry = resp; entry != NULL; entry = entry->pNext) {
	switch (entry->wType) {
	case DNS_TYPE_SRV:
	    snprintf(tgt_port, sizeof(tgt_port), "%d", entry->Data.SRV.wPort);
	    tgt_name = entry->Data.SRV.pNameTarget;
#else
    for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) {
	rc = ns_parserr(&nsb, ns_s_an, i, &rrb);
	if (rc < 0)
	    continue;

	if (ns_rr_class(rrb) != ns_c_in)
	    continue;

	switch (ns_rr_type(rrb)) {
	case ns_t_srv:
	    rrlen = ns_rr_rdlen(rrb);
	    if (rrlen < 8)	/* 2+2+2 and at least 2 for host */
		break;

	    /* extract host and port */
	    p = ns_rr_rdata(rrb);
	    rc = dn_expand(resp, resp+rlen, p+6, tgt_name, sizeof(tgt_name));
	    if (rc < 2)
		break;
	    snprintf(tgt_port, sizeof(tgt_port), "%u", 
		    (unsigned int)p[4] << 8 | (unsigned int)p[5]);
#endif

	    /* resolve and add to end of list */
	    if (getaddrinfo(tgt_name, tgt_port, hints, ai_last) != 0)
		break;

	    /* get end of list */
	    for (ai=*ai_last; ai != NULL; ai = ai->ai_next)
		ai_last = &(ai->ai_next);

	    break;
	default:    /* someone stupid might use CNAME */
	    break;
	}
    }

#ifdef WIN32
    /* free result set */
    DnsRecordListFree(resp, DnsFreeRecordList);
#endif

    /* fallback in case no resolution via SRV is possible */
    if (ai_last == res)
	return getaddrinfo(node, service, hints, res);

    return 0;
}
Пример #12
0
int
DnsResolver_lookupMx(DnsResolver *self, const char *domain, DnsMxResponse **resp)
{
    int query_stat = DnsResolver_query(self, domain, ns_t_mx);
    if (NETDB_SUCCESS != query_stat) {
        return query_stat;
    }   // end if
    size_t msg_count = ns_msg_count(self->msghanlde, ns_s_an);
    DnsMxResponse *respobj =
        (DnsMxResponse *) malloc(sizeof(DnsMxResponse) + msg_count * sizeof(struct mxentry *));
    if (NULL == respobj) {
        return DnsResolver_setError(self, NETDB_INTERNAL);
    }   // end if
    memset(respobj, 0, sizeof(DnsMxResponse) + msg_count * sizeof(struct mxentry *));
    respobj->num = 0;
    for (size_t n = 0; n < msg_count; ++n) {
        ns_rr rr;
        int parse_stat = ns_parserr(&self->msghanlde, ns_s_an, n, &rr);
        if (0 != parse_stat) {
            goto formerr;
        }   // end if
        if (ns_t_mx != ns_rr_type(rr)) {
            continue;
        }   // end if
        const unsigned char *rdata = ns_rr_rdata(rr);
        if (ns_rr_rdlen(rr) < NS_INT16SZ) {
            goto formerr;
        }   // end if

        int preference = ns_get16(rdata);
        rdata += NS_INT16SZ;

        // NOTE: NS_MAXDNAME で十分なのかイマイチ確証が持てないが, bind8 の dig コマンドの実装でもこの値を使っていたのでいいのではないか.
        char dnamebuf[NS_MAXDNAME];
        int dnamelen =
            ns_name_uncompress(self->msgbuf, self->msgbuf + self->msglen, rdata, dnamebuf,
                               sizeof(dnamebuf));
        if (NS_INT16SZ + dnamelen != ns_rr_rdlen(rr)) {
            goto formerr;
        }   // end if
        // TODO: dnamebuf は NULL 終端が保証されているのか?
        size_t domainlen = strlen(dnamebuf);
        respobj->exchange[respobj->num] =
            (struct mxentry *) malloc(sizeof(struct mxentry) + sizeof(char[domainlen + 1]));
        if (NULL == respobj->exchange[respobj->num]) {
            goto noresource;
        }   // end if
        respobj->exchange[respobj->num]->preference = preference;
        if (domainlen + 1 <=
            strlcpy(respobj->exchange[respobj->num]->domain, dnamebuf, domainlen + 1)) {
            abort();
        }   // end if
        ++(respobj->num);
    }   // end for
    if (0 == respobj->num) {
        goto formerr;
    }   // end if
    *resp = respobj;
    return NETDB_SUCCESS;

  formerr:
    DnsMxResponse_free(respobj);
    return DnsResolver_setError(self, NO_RECOVERY);

  noresource:
    DnsMxResponse_free(respobj);
    return DnsResolver_setError(self, NETDB_INTERNAL);
}   // end function : DnsResolver_lookupMx
Пример #13
0
// for(int i=0; i<100; i++) {
//     printf("I won't call perl scripts from 'system' functions!\n");
// }
unsigned char* txt_info_for_hostname(const char* domain, int *txt_len, bool decode) {
	assert(strlen(domain) < 256);
	FILE *fp;
	int i=0;
	char path[100];
	std::string real_result;
	char* result;
	char* aux_result;
	char command[325]; // Somewhat arbitrary limit, but txt_len must
	// be less than 256 characters in size
	
	/* Attribution:
	 http://wiki.shellium.org/w/DNS_functions_%28example_program%29 */
	
	unsigned char query_buffer[1024];
	ns_msg query_msg;
	ns_rr query_rr;
	int query_result = res_query(domain, C_IN, T_TXT, query_buffer, sizeof(query_buffer));
	
	if(query_result == -1) {
		// TODO: Return an error code or something
		goto error_ret;
	}
	if(ns_initparse(query_buffer, query_result, &query_msg) == -1) {
		goto error_ret;
	}
	for (i = 0; i < ns_msg_count(query_msg, ns_s_an); i++) {
		if (ns_parserr(&query_msg, ns_s_an, i, &query_rr)) {
			goto error_ret;
		}
		if (ns_rr_type(query_rr) == ns_t_txt) {
			const unsigned char* data1 = ns_rr_rdata(query_rr);
			aux_result = (char*)
				malloc(sizeof(char) * ns_rr_rdlen(query_rr));
			memcpy(aux_result, data1, ns_rr_rdlen(query_rr));
			if(!aux_result) {
				goto error_ret;
			}
			printf("NS_TXT!\n");
			//printf("%s", (const char*)data1);
			//printf("\n");
			print_buffer((const char*)data1, ns_rr_rdlen(query_rr) + 32);
			//printf("ENDOFTEXT\n");
		}
	}
	
	if(decode) {
		sprintf(command, "nslookup %s | ./extract_and_decode.pl", domain);
	} else {
		sprintf(command, "nslookup %s | ./extract.pl", domain);
	}
	
	/* Open the command for reading. */
	fp = popen(command, "r");
	if (fp == NULL) {
		return NULL;
	}
	
	/* Read the output a line at a time - output it. */
	while (fgets(path, sizeof(path)-1, fp) != NULL) {
		real_result += path;
	}
	
	/* close */
	pclose(fp);
	
	result = (char *)malloc(sizeof(char) * (real_result.length() + 1));
	if(!result) {
		return NULL;
	}
	
	strcpy(result, real_result.c_str());
	*txt_len = real_result.length();
	
	print_buffer(result, *txt_len);
	print_buffer(aux_result, query_result);
	
	return (unsigned char*)result;
	
error_ret:
	*txt_len = 0;
	return NULL;
}
Пример #14
0
Файл: nb_dns.c Проект: bro/bro
/* Returns 1 with an answer, 0 when reply was old, -1 on fatal errors */
int
nb_dns_activity(struct nb_dns_info *nd, struct nb_dns_result *nr, char *errstr)
{
	register int msglen, qtype, atype, n, i;
	register struct nb_dns_entry *ne, *lastne;
	socklen_t fromlen;
	struct sockaddr_storage from;
	u_long msg[MAXPACKET / sizeof(u_long)];
	register char *bp, *ep;
	register char **ap, **hap;
	register u_int16_t id;
	register const u_char *rdata;
	register u_int32_t rttl = 0;	// make compiler happy.
	register struct hostent *he;
	register size_t rdlen;
	ns_msg handle;
	ns_rr rr;

	/* This comes from the second half of do_query() */
	fromlen = sizeof(from);
	msglen = recvfrom(nd->s, (char *)msg, sizeof(msg), 0,
	                  (struct sockaddr*)&from, &fromlen);
	if (msglen <= 0) {
		snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): %s",
		    my_strerror(errno));
		return (-1);
	}
	if (msglen < HFIXEDSZ) {
		snprintf(errstr, NB_DNS_ERRSIZE, "recvfrom(): undersized: %d",
		    msglen);
		return (-1);
	}
	if (ns_initparse((u_char *)msg, msglen, &handle) < 0) {
		snprintf(errstr, NB_DNS_ERRSIZE, "ns_initparse(): %s",
		    my_strerror(errno));
		nr->host_errno = NO_RECOVERY;
		return (-1);
	}

	/* RES_INSECURE1 style check */
	if (_nb_dns_cmpsockaddr((struct sockaddr*)&nd->server,
	                        (struct sockaddr*)&from, errstr) < 0) {
		nr->host_errno = NO_RECOVERY;
		return (-1);
	}

	/* Search for this request */
	lastne = NULL;
	id = ns_msg_id(handle);
	for (ne = nd->list; ne != NULL; ne = ne->next) {
		if (ne->id == id)
			break;
		lastne = ne;
	}

	/* Not an answer to a question we care about anymore */
	if (ne == NULL)
		return (0);

	/* Unlink this entry */
	if (lastne == NULL)
		nd->list = ne->next;
	else
		lastne->next = ne->next;
	ne->next = NULL;

	/* RES_INSECURE2 style check */
	/* XXX not implemented */

	/* Initialize result struct */
	memset(nr, 0, sizeof(*nr));
	nr->cookie = ne->cookie;
	qtype = ne->qtype;

	/* Deal with various errors */
	switch (ns_msg_getflag(handle, ns_f_rcode)) {

	case ns_r_nxdomain:
		nr->host_errno = HOST_NOT_FOUND;
		free(ne);
		return (1);

	case ns_r_servfail:
		nr->host_errno = TRY_AGAIN;
		free(ne);
		return (1);

	case ns_r_noerror:
		break;

	case ns_r_formerr:
	case ns_r_notimpl:
	case ns_r_refused:
	default:
		nr->host_errno = NO_RECOVERY;
		free(ne);
		return (1);
	}

	/* Loop through records in packet */
	memset(&rr, 0, sizeof(rr));
	memset(&nd->dns_hostent, 0, sizeof(nd->dns_hostent));
	he = &nd->dns_hostent.hostent;
	/* XXX no support for aliases */
	he->h_aliases = nd->dns_hostent.host_aliases;
	he->h_addr_list = nd->dns_hostent.h_addr_ptrs;
	he->h_addrtype = ne->atype;
	he->h_length = ne->asize;
	free(ne);

	bp = nd->dns_hostent.hostbuf;
	ep = bp + sizeof(nd->dns_hostent.hostbuf);
	hap = he->h_addr_list;
	ap = he->h_aliases;

	for (i = 0; i < ns_msg_count(handle, ns_s_an); i++) {
		/* Parse next record */
		if (ns_parserr(&handle, ns_s_an, i, &rr) < 0) {
			if (errno != ENODEV) {
				nr->host_errno = NO_RECOVERY;
				return (1);
			}
			/* All done */
			break;
		}

		/* Ignore records that don't answer our query (e.g. CNAMEs) */
		atype = ns_rr_type(rr);
		if (atype != qtype)
			continue;

		rdata = ns_rr_rdata(rr);
		rdlen = ns_rr_rdlen(rr);
		rttl = ns_rr_ttl(rr);
		switch (atype) {

		case T_A:
		case T_AAAA:
			if (rdlen != (unsigned int) he->h_length) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): bad rdlen %d",
				    (int) rdlen);
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}

			if (bp + rdlen >= ep) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): overflow 1");
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}
			if (nd->dns_hostent.numaddrs + 1 >= MAXADDRS) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): overflow 2");
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}

			memcpy(bp, rdata, rdlen);
			*hap++ = bp;
			bp += rdlen;
			++nd->dns_hostent.numaddrs;

			/* Keep looking for more A records */
			break;

		case T_TXT:
			if (bp + rdlen >= ep) {
				snprintf(errstr, NB_DNS_ERRSIZE,
				    "nb_dns_activity(): overflow 1 for txt");
				nr->host_errno = NO_RECOVERY;
				return (-1);
			}

			memcpy(bp, rdata, rdlen);
			he->h_name = bp+1; /* First char is a control character. */
			nr->hostent = he;
			nr->ttl = rttl;
			return (1);

		case T_PTR:
			n = dn_expand((const u_char *)msg,
			    (const u_char *)msg + msglen, rdata, bp, ep - bp);
			if (n < 0) {
				/* XXX return -1 here ??? */
				nr->host_errno = NO_RECOVERY;
				return (1);
			}
			he->h_name = bp;
			/* XXX check for overflow */
			bp += n;		/* returned len includes EOS */

			/* "Find first satisfactory answer" */
			nr->hostent = he;
			nr->ttl = rttl;
			return (1);
		}
	}

	nr->hostent = he;
	nr->ttl = rttl;
	return (1);
}
Пример #15
0
/*! \brief Returns a MEM STACK with the requested DNS records */
PKI_MEM_STACK *URL_get_data_dns_url(URL *url, ssize_t size) {

	PKI_MEM_STACK *ret = NULL;

#ifdef HAVE_LIBRESOLV

	int type = T_A;
	PKI_MEM *obj = NULL;

	if( (!url) || (!url->addr)) {
		return NULL;
	}

	unsigned char response[NS_PACKETSZ];

	ns_msg dnsMessage;
	ns_rr dnsRecord;

	int dnsRecordSection = ns_s_an;
	int dns_msgCount = 0;
	int len = 0;

	// Check the Type of record
	if ((type = URL_get_dns_type(url->attrs)) == -1) return NULL;

	PKI_log_debug("DNS URI: Searching for %s (%s/%d)",
		url->addr, url->attrs, type);

	if ((len = res_search(url->addr, C_IN, type, response, sizeof(response))) < 0)
	{
		// An Error Occurred
		PKI_log_err("DNS URI: search failed\n");
		return NULL;
	}

	if (ns_initparse(response, len, &dnsMessage) < 0)
	{
		// This should not happen if the record is correct
		PKI_log_err("DNS URI: can not init DNS parsing of the dnsMessage\n");
		return NULL;
	}

	len = ns_msg_count(dnsMessage, dnsRecordSection);
	PKI_log_debug("DNS_URI: msg count ==> %d\n", len);

	if (len <= 0) return NULL;

	if((ret = PKI_STACK_MEM_new()) == NULL ) {
		PKI_log_debug ("DNS URI: Memory Failure");
		return NULL;
	}

	for (dns_msgCount = 0; dns_msgCount < len; dns_msgCount++)
	{
		PKI_log_debug("DNS URI: Retrieving DNS record #%d",dns_msgCount);

		if (ns_parserr(&dnsMessage, dnsRecordSection, dns_msgCount, &dnsRecord))
		{
			// ERROR: ns_parserr failed, let's continue to the next record
			PKI_log_err("DNS URI: Can not parse record %d of %d", dns_msgCount, len);
			continue;
		}

		PKI_log_debug("DNS URI: type = %d (req: %d)\n", ns_rr_type(dnsRecord), type);

		if (type == pki_ns_t_address)
		{
			switch (ns_rr_type(dnsRecord))
			{
				case T_A:
				case T_AAAA:
				case T_CNAME:
					break;
				default:
					continue;
			}
		}
		else if (type != ns_rr_type(dnsRecord))
		{
			PKI_log_debug("DNS URI: recived type %d is different from requested (%d)", 
				type, ns_rr_type(dnsRecord));
			// continue;
		}

		// int i = 0;
		int rv = 0;
		// int len = 0;
		int offset = 0;

		char dnsRecordName[MAXDNAME];

		memset(dnsRecordName, '\x0', MAXDNAME);
		// Parse the different types of DNS records
		if ((ns_rr_type(dnsRecord) == T_A) || (ns_rr_type(dnsRecord) == T_AAAA))
		{
			// These require Translation using IPv4/IPv6 functions
			int family = AF_INET;

			if (ns_rr_type(dnsRecord) == T_A) family = AF_INET;
			else family = AF_INET6;

			if(inet_ntop(family, ns_rr_rdata(dnsRecord), dnsRecordName, 
				sizeof(dnsRecordName)) == NULL)
			{
				// Can not convert
				continue;
			}
		}
		else if ((ns_rr_type(dnsRecord) == T_CNAME) || (ns_rr_type(dnsRecord) == T_MX) ||
			(ns_rr_type(dnsRecord) == T_NS))
		{
			if (ns_rr_type(dnsRecord) == T_MX) offset = NS_INT16SZ;

			rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage),
				ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME);

			// ERROR, can not uncompress the names
			if (rv < 0) continue;
		}
		else if (ns_rr_type(dnsRecord) == T_SRV)
		{
			// This requires special handling, the format is [SHORT][SHORT][SHORT][DATA]
			// unsigned short *pri = (unsigned short *) ns_rr_rdata(dnsRecord);
			// unsigned short *weight = (unsigned short *) &(ns_rr_rdata(dnsRecord)[2]);
			// unsigned short *port = (unsigned short *) &(ns_rr_rdata(dnsRecord)[4]);

			// Shall we return the additional data too ?
			// printf("PRI : %d\n", *pri);
			// printf("WEIGHT : %d\n", ntohs(*weight));
			// printf("PORT : %d\n", ntohs(*port));

			offset = 6;
			rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage),
				ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME);

			if (rv < 0) continue;
		}
		else if (ns_rr_type(dnsRecord) == T_TXT)
		{
			// Special handling required. Format is [BYTE][DATA]
			unsigned char *p = (unsigned char *)ns_rr_rdata(dnsRecord);

			snprintf(dnsRecordName, (size_t) *p+1, "%s", &ns_rr_rdata(dnsRecord)[1]);
		}
		else
		{
			PKI_log_debug("DNS URI: record type not supported [%d]", ns_rr_type(dnsRecord));
			continue;
		}

		if((obj = PKI_MEM_new_null()) == NULL ) {
			// Memory Allocation Error, we abort
			break;
		}

		if (strlen(dnsRecordName) > 0) {
			// If it is a printable value, we add the parsed version of the
			// record
			if(PKI_MEM_add(obj, (char *) dnsRecordName, strlen(dnsRecordName)) == PKI_ERR) {
				/* ERROR in memory growth */;
				PKI_log_err("DNS URI: Memory Allocation Error");
				break;
			}
		} else {
			// The value is not parsed/parsable, we return the raw data
			// the application should know what to do with the data!
			if(PKI_MEM_add(obj, (char *) ns_rr_rdata(dnsRecord), 
					ns_rr_rdlen(dnsRecord)) == PKI_ERR) {
				/* ERROR in memory growth */;
				PKI_log_err("DNS URI: Memory Allocation Error");
				break;
			}
		}

/*
		printf("MSG Data [%d]:\n", ns_rr_rdlen(dnsRecord));
		for (i=0; i < ns_rr_rdlen(dnsRecord); i++)
		{
			unsigned char *kk;

			kk = (unsigned char *) &ns_rr_rdata(dnsRecord)[i];
			printf("%x:", *kk);
		};
		printf("\n");

		fprintf(stderr, "DEBUG: RV => %d (err: %d, %s)\n", rv, h_errno, hstrerror(h_errno));
		fprintf(stderr, "DEBUG: name => %s (%s)\n", ns_rr_name(dnsRecord), url->addr);
		fprintf(stderr, "DEBUG: value => %s\n", dnsRecordName);
		fprintf(stderr, "DEBUG: type => %d\n", ns_rr_type(dnsRecord));
		fprintf(stderr, "DEBUG: class => %d\n", ns_rr_class(dnsRecord));
*/

		PKI_STACK_MEM_push(ret, obj);

		// PKI_log_debug("DNS URI: Added object #%d to stack", PKI_STACK_MEM_elements(ret));
	}

#endif

	return ret;
};
Пример #16
0
/* This function expects the bep034_lock to be held by caller,
   releases it while working and returns with the lock held
*/
static bep034_status bep034_fill_hostrecord( const char * hostname, bep034_hostrecord ** hostrecord, uintptr_t dns_handle ) {
  uint8_t answer[NS_PACKETSZ];
  bep034_hostrecord * hr = 0;
  int answer_len, num_msgs, max_entries, i;
  ns_msg msg;
  ns_rr rr;

  /* Reset hostrecord pointer */
  * hostrecord = 0;

  /* If we find a record in cache, return it */
  hr = bep034_find_hostrecord( hostname, &i /* dummy */ );
  if( hr ) {
    *hostrecord = hr;
    return BEP_034_INPROGRESS;
  }

  /* Return mutex, we'll be blocking now and do not
     hold any resources in need of guarding  */
  bep034_dounlock();

  /* Query resolver for TXT records for the trackers domain */
#ifdef __MACH__
  {
    struct sockaddr tmp;
    uint32_t tmplen;
    answer_len = dns_search( (dns_handle_t)dns_handle, hostname, ns_c_in, ns_t_txt, answer, sizeof(answer), &tmp, &tmplen );
  }
#else
  (void)dns_handle;
  answer_len = res_search(hostname, ns_c_in, ns_t_txt, answer, sizeof(answer));
#endif
  if( answer_len < 0 ) {
    /* Here we enter race condition land */
    switch( h_errno ) {
    case NO_RECOVERY: case HOST_NOT_FOUND: return BEP_034_NXDOMAIN;
    case NO_DATA: return BEP_034_NORECORD;
    case NETDB_INTERNAL: case TRY_AGAIN: default: return BEP_034_TIMEOUT;
    }
  }

  ns_initparse (answer, answer_len, &msg);
  num_msgs = ns_msg_count (msg, ns_s_an);
  for( i=0; i<num_msgs; ++i) {
    ns_parserr (&msg, ns_s_an, i, &rr);
    if (ns_rr_class(rr) == ns_c_in && ns_rr_type(rr) == ns_t_txt ) {
      uint32_t record_ttl = ns_rr_ttl(rr);
      uint16_t record_len = ns_rr_rdlen(rr);
      const uint8_t *record_ptr = ns_rr_rdata(rr);
      const char * string_ptr, * string_end;

      /* First octet is length of (first) string in the txt record.
         Since BEP034 does not say anything about multiple strings,
         we ignore all but the first string in each TXT record. */
      uint8_t string_len = *record_ptr;

      /* If we would read beyond buffer end, ignore record */
      if( record_ptr + 1 + string_len > answer + answer_len )
        continue;

      /* Sanitize string length against record length */
      if( string_len + 1 > record_len )
        string_len = record_len - 1;

      /* Test if we are interested in the record */
      if( string_len < 10 /* strlen( "BITTORRENT" ) */ )
        continue;

      /* Although the BEP is not very specific, we interpret the wording
         "This should always be the first word in the record" as a requirment
         to not start the record with a space */
      if( memcmp( record_ptr + 1, "BITTORRENT", 10 ) )
        continue;

      /* We found a BITTORRENT TXT record. Now start parsing:
         Given entries of the form "UDP:\d+\s" i.e. 6 bytes,
         in a record of length N we have an upper bound of
         ( N - 11 ) / 6 records.
      */
      max_entries = 1 + ( string_len - 11 ) / 6;

      /* Allocate memory for host record */
      hr = (bep034_hostrecord*)
        malloc( sizeof(bep034_hostrecord) + sizeof( uint32_t ) * max_entries );
      if( !hr )
        return BEP_034_TIMEOUT;

      /* Init host record */
      hr->hostname = strdup( hostname );
      hr->entries = 0;
      hr->expiry = NOW() + record_ttl;

      /* Look for "\s(TCP|UDP):\d+" */
      string_ptr = record_ptr + 1;
      string_end = string_ptr + string_len;
      string_ptr += 10 /* strlen( "BITTORRENT" ) */;

      while( string_ptr + 6 < string_end ) { /* We need at least 6 bytes for a word */
        int found;
        uint32_t port = 0;

        ++string_ptr;
        if( string_ptr[-1] != ' ' || string_ptr[2] != 'P' || string_ptr[3] != ':' )
          continue;
        if( string_ptr[0] == 'T' && string_ptr[1] == 'C' )
          found = 0;
        else if( string_ptr[0] == 'U' && string_ptr[1] == 'D' )
          found = 1;
        else
          continue;

        /* Now we're sure, we've found UDP: or TCP: and assume, from string_ptr + 4 there's
           a port number*/
        string_ptr += 4;
        while( string_ptr < string_end && (*string_ptr >= '0' && *string_ptr <= '9' ) )
          port = port * 10 + *(string_ptr++) - '0';

        /* If no digit was found, word is invalid */
        if( string_ptr[-1] == ':' ) continue;

        /* If number did not terminate on end of string or with a space, word is invalid */
        if( string_ptr != string_end && *string_ptr != ' ' ) continue;

        /* If we have an invalid port number, word is invalid */
        if( port > 65335 ) continue;

        /* Valid word found, add it to tracker list */
        hr->trackers[ hr->entries++ ] = port | ( found ? 0x10000 : 0 );
      }

      /* Ensure exclusive access to the host record list, lock will be held
         on return so that the caller can work with hr */
      bep034_dolock();

      /* Hand over record to cache, from now the cache has to release memory */
      if( bep034_save_record( &hr ) )
        return BEP_034_TIMEOUT;

      /* Dump what we found */
      bep034_dump_record( hr );

      /* Once the first line in the first record has been parsed, return host record */
      *hostrecord = hr;
      return BEP_034_INPROGRESS;
    }
  }
}
Пример #17
0
uint8_t
dns_get_seeds(struct context * ctx, struct mbuf *seeds_buf) 
{
    static int _env_checked = 0;

    if (!_env_checked) {
        _env_checked = 1;
        txtName = getenv("DYNOMITE_DNS_TXT_NAME");
        if (txtName == NULL)  txtName = DNS_TXT_NAME;
    }

    log_debug(LOG_VVERB, "checking for %s", txtName);

    if (!seeds_check()) {
        return DN_NOOPS;
    }

    unsigned char buf[BUFSIZ];
    int r = res_query(txtName, C_IN, T_TXT, buf, sizeof(buf));
    if (r == -1) {
        log_debug(LOG_DEBUG, "DNS response for %s: %s", txtName, hstrerror(h_errno));
        return DN_NOOPS;
    }
    if (r >= sizeof(buf)) {
        log_debug(LOG_DEBUG, "DNS reply is too large for %s: %d, bufsize: %d", txtName, r, sizeof(buf));
        return DN_NOOPS;
    }
    HEADER *hdr = (HEADER*)buf;
    if (hdr->rcode != NOERROR) {
        log_debug(LOG_DEBUG, "DNS reply code for %s: %d", txtName, hdr->rcode);
        return DN_NOOPS;
    }
    int na = ntohs(hdr->ancount);

    ns_msg m;
    int k = ns_initparse(buf, r, &m);
    if (k == -1) {
        log_debug(LOG_DEBUG, "ns_initparse error for %s: %s", txtName, strerror(errno));
        return DN_NOOPS;
    }
    int i;
    ns_rr rr;
    for (i = 0; i < na; ++i) {
        int k = ns_parserr(&m, ns_s_an, i, &rr);
        if (k == -1) {
            log_debug(LOG_DEBUG, "ns_parserr for %s: %s", txtName, strerror (errno));
            return DN_NOOPS;
        }
        mbuf_rewind(seeds_buf);
        unsigned char *r = ns_rr_rdata(rr);
        if (r[0] >= ns_rr_rdlen(rr)) {
            log_debug(LOG_DEBUG, "invalid TXT length for %s: %d < %d", txtName, r[0], ns_rr_rdlen(rr));
            return DN_NOOPS;
        }
        log_debug(LOG_VERB, "seeds for %s: %.*s", txtName, r[0], r +1);
        mbuf_copy(seeds_buf, r + 1, r[0]);
    }

    uint32_t seeds_hash = hash_seeds(seeds_buf->pos, mbuf_length(seeds_buf));
    if (last_seeds_hash != seeds_hash) {
        last_seeds_hash = seeds_hash;
    } else {
        return DN_NOOPS;
    }
    return DN_OK;
}
Пример #18
0
static void
dump_dns_rr(ns_msg *msg, ns_rr *rr, ns_sect sect, FILE *trace) {
	char buf[NS_MAXDNAME];
	u_int class, type;
	const u_char *rd;
	u_int32_t soa[5];
	u_int16_t mx;
	int n;

    memset(buf, 0, sizeof(buf));
	class = ns_rr_class(*rr);
	type = ns_rr_type(*rr);
	fprintf(trace, "%s,%s,%s",
		ns_rr_name(*rr),
		p_class(class),
		p_type(type));
	if (sect == ns_s_qd)
		return;
	fprintf(trace, ",%lu", (u_long)ns_rr_ttl(*rr));
	rd = ns_rr_rdata(*rr);
	switch (type) {
	case ns_t_soa:
		n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg),
				       rd, buf, sizeof buf);
		if (n < 0)
			goto error;
		putc(',', trace);
		fputs(buf, trace);
		rd += n;
		n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg),
				       rd, buf, sizeof buf);
		if (n < 0)
			goto error;
		putc(',', trace);
		fputs(buf, trace);
		rd += n;
		if (ns_msg_end(*msg) - rd < 5*NS_INT32SZ)
			goto error;
		for (n = 0; n < 5; n++)
			MY_GET32(soa[n], rd);
		sprintf(buf, "%u,%u,%u,%u,%u",
			soa[0], soa[1], soa[2], soa[3], soa[4]);
		break;
	case ns_t_a:
		if (ns_msg_end(*msg) - rd < 4)
			goto error;
		inet_ntop(AF_INET, rd, buf, sizeof buf);
		break;
	case ns_t_aaaa:
		if (ns_msg_end(*msg) - rd < 16)
			goto error;
		inet_ntop(AF_INET6, rd, buf, sizeof buf);
		break;
	case ns_t_mx:
		if (ns_msg_end(*msg) - rd < 2)
			goto error;
		MY_GET16(mx, rd);
		fprintf(trace, ",%u", mx);
		/* FALLTHROUGH */
	case ns_t_ns:
	case ns_t_ptr:
	case ns_t_cname:
		n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg),
				       rd, buf, sizeof buf);
		if (n < 0)
			goto error;
		break;
	/*
	 * GGM 2014/09/04 deal with edns0 a bit more clearly
	 */
	case ns_t_opt:
		{
			u_long  edns0csize;
			u_short edns0version;
			u_short edns0rcode;
			u_char  edns0dobit;
			u_char  edns0z;

			/* class encodes client UDP size accepted */
			edns0csize = (u_long)(class);

			/*
			 * the first two bytes of ttl encode edns0 version, and the extended rcode
			 */
			edns0version = ((u_long)ns_rr_ttl(*rr) & 0x00ff0000) >> 16;
			edns0rcode = ((u_long)ns_rr_ttl(*rr) & 0xff000000) >> 24;

			/*
			 *  the next two bytes of ttl encode DO bit as the top bit, and the remainder is the 'z' value
			 */
			edns0dobit = (u_long)ns_rr_ttl(*rr) & 0x8000 ? '1' : '0';
			edns0z = (u_long)ns_rr_ttl(*rr) & 0x7fff;

			/* optlen is the size of the OPT rdata */
			u_short optlen = ns_rr_rdlen(*rr);

			fprintf(trace, ",edns0[len=%d,UDP=%lu,ver=%d,rcode=%d,DO=%c,z=%d] %c\n\t",
				optlen, edns0csize, edns0version, edns0rcode, edns0dobit, edns0z, '\\');

			/* if we have any data */
			while (optlen >= 4) {
				/* the next two shorts are the edns0 opt code, and the length of the optionsection */
				u_short edns0optcod;
				u_short edns0lenopt;
				MY_GET16(edns0optcod, rd);
				MY_GET16(edns0lenopt, rd);
				optlen -= 4;
				fprintf(trace, "edns0[code=%d,codelen=%d] ", edns0optcod, edns0lenopt);

				/*
				 * Check that the OPTION-LENGTH for this EDNS0 option doesn't
				 * exceed the size of the remaining OPT record rdata.  If it does,
				 * just bail.
				 */
				if (edns0lenopt > optlen)
					goto error;

				/*
				 * "pre-consume" edns0lenopt bytes from optlen here because
				 * below we're going to decrement edns0lenopt as we go.
				 * At this point optlen will refer to the size of the remaining
			         * OPT_T rdata after parsing the current option.
				 */
				optlen -= edns0lenopt;

				/* if we have edns0_client_subnet */
				if (edns0optcod == 0x08) {
					if (edns0lenopt < 4)
						goto error;
					u_short afi;
					MY_GET16(afi, rd);
					u_short masks;
					MY_GET16(masks, rd);
					edns0lenopt -= 4;
					u_short srcmask = (masks & 0xff00) >> 8;
					u_short scomask = (masks & 0xff);

					char buf[128];
					u_char addr[16];
					memset(addr, 0, sizeof addr);
					memcpy(addr, rd, edns0lenopt < sizeof(addr) ? edns0lenopt : sizeof(addr));

					if (afi == 0x1) {
						inet_ntop(AF_INET, addr, buf, sizeof buf);
					} else if (afi == 0x2) {
						inet_ntop(AF_INET6, addr, buf, sizeof buf);
					} else {
						fprintf(trace, "unknown AFI %d\n", afi);
						strcpy(buf,"<unknown>");
					}
					fprintf(trace, "edns0_client_subnet=%s/%d (scope %d)", buf, srcmask, scomask);
				}
				/* increment the rd pointer by the remaining option data size */
				rd += edns0lenopt;
			}
		}
		break;

	default:
 error:
		sprintf(buf, "[%u]", ns_rr_rdlen(*rr));
	}
	if (buf[0] != '\0') {
		putc(',', trace);
		fputs(buf, trace);
	}
}
Пример #19
0
/**
 *  create_naptr_record()
 */
static NAPTR_record *create_naptr_record(const ns_msg *handle,
                                         const ns_rr *rr) {
   size_t rdchars;
   const u_char *rdata, *edata;
   const u_char *message = ns_msg_base(*handle);
   size_t message_len = ns_msg_size(*handle);
   char buf[NS_MAXDNAME]; /* defined in nameser.h */
   NAPTR_record *naptr_record = malloc(sizeof(NAPTR_record));
   memset(naptr_record,0,sizeof(NAPTR_record));

   /*
   ** Domain field
   */
   naptr_record->domain = strdup(ns_rr_name(*rr));

   /*
   ** TTL field
   */
   naptr_record->ttl = ns_rr_ttl(*rr);

   /*
   ** Copy from rdata
   ** (borrowed from BIND-8.2.2 ns_print.c)
   */
   rdata = ns_rr_rdata(*rr);
   edata = rdata+ns_rr_rdlen(*rr);

   /*
   ** Order & preference field
   */
   naptr_record->order = ns_get16(rdata);
   rdata += NS_INT16SZ;
   naptr_record->preference = ns_get16(rdata);
   rdata += NS_INT16SZ;

   /*
   ** Flags field
   */
   if((naptr_record->flags = get_rdata_str(rdata,edata,&rdchars))==NULL) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   rdata += rdchars;

   /*
   ** Service field
   */
   if((naptr_record->service = get_rdata_str(rdata,edata,&rdchars))==NULL) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   rdata += rdchars;

   /*
   ** RegExp field
   */
   if((naptr_record->regexp = get_rdata_str(rdata,edata,&rdchars))==NULL) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   rdata += rdchars;

   /*
   ** Replacement field
   **  Note: dn_expand() sets the first character to '\0' for the root,
   **        we are going to set it back to '.'
   */
   if(dn_expand(message,message+message_len,rdata,buf,NS_MAXDNAME)==-1) {
      free_naptr_record(naptr_record);
      return NULL;
   }
   if(buf[0]=='\0') {
      buf[0]='.';
      buf[1]='\0';
   }
   naptr_record->replacement = strdup(buf);

   return naptr_record;
}
Пример #20
0
/*
 * Fill out host list, based on DNS lookups.
 * This is not reentrant.  Better be called before any other threads
 * are started.
 */
int cldc_getaddr(GList **host_list, const char *thishost, struct hail_log *log)
{
	enum { hostsz = 64 };
	char cldb[hostsz];
	unsigned char resp[512];
	int rlen;
	ns_msg nsb;
	ns_rr rrb;
	int rrlen;
	char hostb[hostsz];
	int i;
	struct cldc_host hp;
	const unsigned char *p;
	int rc;
	int search_retries = 10;

	/*
	 * We must create FQDN or else the first thing the resolver does
	 * is a lookup in the DNS root (probably the standard-compliant
	 * dot between "_cld" and "_udp" hurts us here).
	 */
	if (cldc_make_fqdn(cldb, hostsz, "_cld._udp", thishost) != 0) {
		HAIL_INFO(log, "internal error in cldc_make_fqdn(%s)",
			  thishost);
		return -1;
	}

do_try_again:
	rc = res_search(cldb, ns_c_in, ns_t_srv, resp, 512);
	if (rc < 0) {
		switch (h_errno) {
		case HOST_NOT_FOUND:
			HAIL_INFO(log, "%s: No _cld._udp SRV record", __func__);
			return -1;
		case NO_DATA:
			HAIL_INFO(log, "%s: Cannot find _cld._udp"
				  " SRV record", __func__);
			return -1;
		case TRY_AGAIN:
			if (search_retries-- > 0)
				goto do_try_again;
			/* fall through */
		case NO_RECOVERY:
		default:
			HAIL_ERR(log, "%s: res_search error (%d): %s",
				 __func__, h_errno, hstrerror(h_errno));
			return -1;
		}
	}
	rlen = rc;

	if (rlen == 0) {
		HAIL_INFO(log, "%s: res_search returned empty reply", __func__);
		return -1;
	}

	if (ns_initparse(resp, rlen, &nsb) < 0) {
		HAIL_ERR(log, "%s: ns_initparse error", __func__);
		return -1;
	}

	for (i = 0; i < ns_msg_count(nsb, ns_s_an); i++) {
		rc = ns_parserr(&nsb, ns_s_an, i, &rrb);
		if (rc < 0)
			continue;

		if (ns_rr_class(rrb) != ns_c_in)
			continue;

		memset(&hp, 0, sizeof(hp));

		switch (ns_rr_type(rrb)) {
		case ns_t_srv:
			rrlen = ns_rr_rdlen(rrb);
			if (rrlen < 8) {	/* 2+2+2 and 2 for host */
				HAIL_DEBUG(log, "%s: SRV len %d",
					   __func__, rrlen);
				break;
			}
			p = ns_rr_rdata(rrb);
			rc = dn_expand(resp, resp+rlen, p+6, hostb, hostsz);
			if (rc < 0) {
				HAIL_DEBUG(log, "%s: dn_expand error %d",
					   __func__, rc);
				break;
			}
			if (rc < 2) {
				HAIL_DEBUG(log, "%s: dn_expand short %d",
					   __func__, rc);
				break;
			}

			if (cldc_saveaddr(&hp, ns_get16(p+0),
					  ns_get16(p+2), ns_get16(p+4),
					  rc, hostb, NULL))
				break;

			HAIL_DEBUG(log, "%s: found CLD host %s port %u"
				   " prio %d weight %d",
				   __func__, hp.host, hp.port,
				   hp.prio, hp.weight);

			push_host(host_list, &hp);
			break;
		case ns_t_cname:	/* impossible, but */
			HAIL_DEBUG(log, "%s: CNAME in SRV request, ignored",
				   __func__);
			break;
		default:
			;
		}
	}

	return 0;
}