예제 #1
0
파일: process_query.c 프로젝트: idtek/knot
/* Resolve query and check answer for sanity (2 TAP tests). */
static void exec_query(knot_layer_t *query_ctx, const char *name,
                       knot_pkt_t *query,
                       uint8_t expected_rcode)
{
	knot_pkt_t *answer = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
	assert(answer);

	/* Input packet. */
	knot_pkt_parse(query, 0);
	int state = knot_layer_consume(query_ctx, query);

	ok(state & (KNOT_STATE_PRODUCE|KNOT_STATE_FAIL), "ns: process %s query", name);

	/* Create answer. */
	state = knot_layer_produce(query_ctx, answer);
	if (state & KNOT_STATE_FAIL) {
		/* Allow 1 generic error response. */
		state = knot_layer_produce(query_ctx, answer);
	}

	ok(state == KNOT_STATE_DONE, "ns: answer %s query", name);

	/* Check answer. */
	answer_sanity_check(query->wire, answer->wire, answer->size, expected_rcode, name);

	knot_pkt_free(&answer);
}
예제 #2
0
파일: pkt.c 프로젝트: gitter-badger/knot
_public_
int knot_pkt_copy(knot_pkt_t *dst, const knot_pkt_t *src)
{
	if (dst == NULL || src == NULL) {
		return KNOT_EINVAL;
	}

	if (dst->max_size < src->size) {
		return KNOT_ESPACE;
	}

	dst->size = src->size;
	memcpy(dst->wire, src->wire, dst->size);

	/* Copy TSIG RR back to wire. */
	if (src->tsig_rr) {
		int ret = knot_tsig_append(dst->wire, &dst->size, dst->max_size,
		                           src->tsig_rr);
		if (ret != KNOT_EOK) {
			return ret;
		}
	}

	/* Invalidate arrays . */
	dst->rr = NULL;
	dst->rr_info = NULL;
	dst->rrset_count = 0;
	dst->rrset_allocd = 0;

	/* @note This could be done more effectively if needed. */
	return knot_pkt_parse(dst, 0);
}
예제 #3
0
static int request_io(struct knot_requestor *req, struct knot_request *last,
                      struct timeval *timeout)
{
	int ret = KNOT_EOK;
	knot_pkt_t *query = last->query;
	knot_pkt_t *resp = last->resp;

	/* Data to be sent. */
	if (req->overlay.state == KNOT_STATE_PRODUCE) {

		/* Process query and send it out. */
		knot_overlay_produce(&req->overlay, query);

		if (req->overlay.state == KNOT_STATE_CONSUME) {
			ret = request_send(last, timeout);
			if (ret != KNOT_EOK) {
				return ret;
			}
		}
	}

	/* Data to be read. */
	if (req->overlay.state == KNOT_STATE_CONSUME) {
		/* Read answer and process it. */
		ret = request_recv(last, timeout);
		if (ret < 0) {
			return ret;
		}

		(void) knot_pkt_parse(resp, 0);
		knot_overlay_consume(&req->overlay, resp);
	}

	return KNOT_EOK;
}
예제 #4
0
파일: tcp-handler.c 프로젝트: idtek/knot
/*!
 * \brief TCP event handler function.
 */
static int tcp_handle(tcp_context_t *tcp, int fd,
                      struct iovec *rx, struct iovec *tx)
{
	/* Create query processing parameter. */
	struct sockaddr_storage ss;
	memset(&ss, 0, sizeof(struct sockaddr_storage));
	struct process_query_param param = {0};
	param.socket = fd;
	param.remote = &ss;
	param.server = tcp->server;
	param.thread_id = tcp->thread_id;
	rx->iov_len = KNOT_WIRE_MAX_PKTSIZE;
	tx->iov_len = KNOT_WIRE_MAX_PKTSIZE;

	/* Receive peer name. */
	socklen_t addrlen = sizeof(struct sockaddr_storage);
	if (getpeername(fd, (struct sockaddr *)&ss, &addrlen) < 0) {
		;
	}

	/* Timeout. */
	rcu_read_lock();
	conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
	int timeout = conf_int(val) * 1000;
	rcu_read_unlock();

	/* Receive data. */
	int ret = net_dns_tcp_recv(fd, rx->iov_base, rx->iov_len, timeout);
	if (ret <= 0) {
		if (ret == KNOT_EAGAIN) {
			char addr_str[SOCKADDR_STRLEN] = {0};
			sockaddr_tostr(addr_str, sizeof(addr_str), &ss);
			log_warning("TCP, connection timed out, address '%s'",
			            addr_str);
		}
		return KNOT_ECONNREFUSED;
	} else {
		rx->iov_len = ret;
	}

	knot_mm_t *mm = tcp->overlay.mm;

	/* Initialize processing overlay. */
	ret = knot_overlay_init(&tcp->overlay, mm);
	if (ret != KNOT_EOK) {
		return ret;
	}
	ret = knot_overlay_add(&tcp->overlay, NS_PROC_QUERY, &param);
	if (ret != KNOT_EOK) {
		return ret;
	}

	/* Create packets. */
	knot_pkt_t *ans = knot_pkt_new(tx->iov_base, tx->iov_len, mm);
	knot_pkt_t *query = knot_pkt_new(rx->iov_base, rx->iov_len, mm);

	/* Input packet. */
	(void) knot_pkt_parse(query, 0);
	int state = knot_overlay_consume(&tcp->overlay, query);

	/* Resolve until NOOP or finished. */
	ret = KNOT_EOK;
	while (state & (KNOT_STATE_PRODUCE|KNOT_STATE_FAIL)) {
		state = knot_overlay_produce(&tcp->overlay, ans);

		/* Send, if response generation passed and wasn't ignored. */
		if (ans->size > 0 && !(state & (KNOT_STATE_FAIL|KNOT_STATE_NOOP))) {
			if (net_dns_tcp_send(fd, ans->wire, ans->size, timeout) != ans->size) {
				ret = KNOT_ECONNREFUSED;
				break;
			}
		}
	}

	/* Reset after processing. */
	knot_overlay_finish(&tcp->overlay);
	knot_overlay_deinit(&tcp->overlay);

	/* Cleanup. */
	knot_pkt_free(&query);
	knot_pkt_free(&ans);

	return ret;
}