Esempio n. 1
0
static int reply_recv(struct dnsc *dnsc, struct mbuf *mb)
{
	struct dns_query *q = NULL;
	uint32_t i, j, nv[3];
	struct dnsquery dq;
	int err = 0;

	if (!dnsc || !mb)
		return EINVAL;

	dq.name = NULL;

	if (dns_hdr_decode(mb, &dq.hdr) || !dq.hdr.qr) {
		err = EBADMSG;
		goto out;
	}

	err = dns_dname_decode(mb, &dq.name, 0);
	if (err)
		goto out;

	if (mbuf_get_left(mb) < 4) {
		err = EBADMSG;
		goto out;
	}

	dq.type     = ntohs(mbuf_read_u16(mb));
	dq.dnsclass = ntohs(mbuf_read_u16(mb));

	q = list_ledata(hash_lookup(dnsc->ht_query, hash_joaat_str_ci(dq.name),
				    query_cmp_handler, &dq));
	if (!q) {
		err = ENOENT;
		goto out;
	}

	/* try next server */
	if (dq.hdr.rcode == DNS_RCODE_SRV_FAIL && q->ntx < *q->srvc) {

		if (!q->tc) /* try next UDP server immediately */
			tmr_start(&q->tmr, 0, udp_timeout_handler, q);

		err = EPROTO;
		goto out;
	}

	nv[0] = dq.hdr.nans;
	nv[1] = dq.hdr.nauth;
	nv[2] = dq.hdr.nadd;

	for (i=0; i<ARRAY_SIZE(nv); i++) {

		for (j=0; j<nv[i]; j++) {

			struct dnsrr *rr = NULL;

			err = dns_rr_decode(mb, &rr, 0);
			if (err) {
				query_handler(q, err, NULL, NULL, NULL, NULL);
				mem_deref(q);
				goto out;
			}

			list_append(&q->rrlv[i], &rr->le_priv, rr);
		}
	}

	if (q->type == DNS_QTYPE_AXFR) {

		struct dnsrr *rrh, *rrt;

		rrh = list_ledata(list_head(&q->rrlv[0]));
		rrt = list_ledata(list_tail(&q->rrlv[0]));

		/* Wait for last AXFR reply with terminating SOA record */
		if (dq.hdr.rcode == DNS_RCODE_OK && dq.hdr.nans > 0 &&
		    (!rrt || rrt->type != DNS_TYPE_SOA || rrh == rrt)) {
			DEBUG_INFO("waiting for last SOA record in reply\n");
			goto out;
		}
	}

	query_handler(q, 0, &dq.hdr, &q->rrlv[0], &q->rrlv[1], &q->rrlv[2]);
	mem_deref(q);

 out:
	mem_deref(dq.name);

	return err;
}
Esempio n. 2
0
static void decode_dns_query(struct dns_server *srv,
			     const struct sa *src, struct mbuf *mb)
{
	struct list rrl = LIST_INIT;
	struct dnshdr hdr;
	struct le *le;
	char *qname = NULL;
	size_t start, end;
	uint16_t type, dnsclass;
	int err = 0;

	start = mb->pos;
	end   = mb->end;

	if (dns_hdr_decode(mb, &hdr) || hdr.qr || hdr.nq != 1) {
		DEBUG_WARNING("unable to decode query header\n");
		return;
	}

	err = dns_dname_decode(mb, &qname, start);
	if (err) {
		DEBUG_WARNING("unable to decode query name\n");
		goto out;
	}

	if (mbuf_get_left(mb) < 4) {
		err = EBADMSG;
		DEBUG_WARNING("unable to decode query type/class\n");
		goto out;
	}

	type     = ntohs(mbuf_read_u16(mb));
	dnsclass = ntohs(mbuf_read_u16(mb));

	DEBUG_INFO("dnssrv: type=%s query-name='%s'\n",
		   dns_rr_typename(type), qname);

	if (dnsclass == DNS_CLASS_IN) {
		dns_server_match(srv, &rrl, qname, type);
	}

	hdr.qr    = true;
	hdr.tc    = false;
	hdr.rcode = DNS_RCODE_OK;
	hdr.nq    = 1;
	hdr.nans  = list_count(&rrl);

	mb->pos = start;

	err = dns_hdr_encode(mb, &hdr);
	if (err)
		goto out;

	mb->pos = end;

	DEBUG_INFO("dnssrv: @@ found %u answers for %s\n",
		   list_count(&rrl), qname);

	for (le = rrl.head; le; le = le->next) {
		struct dnsrr *rr = le->data;

		err = dns_rr_encode(mb, rr, 0, NULL, start);
		if (err)
			goto out;
	}

	mb->pos = start;

	(void)udp_send(srv->us, src, mb);

 out:
	list_clear(&rrl);
	mem_deref(qname);
}