示例#1
0
int tcp_response_waiting_client_close_process (Context *cont) {
	const char *fn = "tcp_response_waiting_client_close_process()";
	uint16_t length_buf;
	int i;

	syslog (LOG_DEBUG, "%s: start", fn);

	i = read (cont->conn_sock, (u_char *) (&length_buf),
		  sizeof (uint16_t));
	if (!i) /* SUCCESS */
		return tcp_response_finish (cont);

	if (i < sizeof (uint16_t)) {
		/* read error */
		syslog (LOG_INFO, "%s: read(): %m", fn);
		return (response_abort (cont, -1));
	}

	/* redo query processing */
	length_buf = ntohs (length_buf);
	syslog (LOG_DEBUG, "%s: incoming length %d", fn, length_buf);

	/* free old buffer */
	if (cont->mesg.p)
		free (cont->mesg.p);

	/* allocate new buffer */
	cont->mesg.p = malloc (length_buf);
	if (!cont->mesg.p) {
		cont->mesg_len = 0;
		return (response_abort (cont, -1));
	}

	cont->mesg_len = length_buf;
	cont->wp = cont->mesg.p;
	cont->timeout = TCP_SRV_TIMEOUT;

	/* renew timeout */
	if (cont->tout)
		cont->tout->handler = NULL;

	if (context_timeout_register (cont, cont->timeout))
		return (response_abort (cont, -1));

	/*
	 * I/O event is not changed -- tcp_conn_in,
	 * go back to reading
	 */

	cont->process = tcp_response_reading_process;
	cont->retry = tcp_response_reading_retry;

	syslog (LOG_DEBUG, "%s: return, continue reading", fn);

	/* SUCCESS, but not FINISHED yet */
	return 0;
}
示例#2
0
int tcp_response_readlen_process (Context *cont) {
	const char *fn = "tcp_response_readlen_process()";
	uint16_t length_buf;

	syslog (LOG_DEBUG, "%s: start", fn);

	/* renew timeout */
	if (cont->tout)
		cont->tout->handler = NULL;

	if (context_timeout_register (cont, cont->timeout))
		return (response_abort (cont, -1));

	/* still use old input list -- data following */

	/* read length buffer */
	if (read (cont->conn_sock, (u_char *) (&length_buf),
	    sizeof (uint16_t)) < sizeof (uint16_t)) {
		syslog (LOG_NOTICE, "%s: cannot read length TCP message", fn);
		return (response_abort (cont, -1));
	}

	length_buf = ntohs (length_buf);
	syslog (LOG_DEBUG, "%s: data length = %d", fn, length_buf);

	/* free old buffer */
	if (cont->mesg.p)
		free (cont->mesg.p);

	/* allocate new properly sized buffer */
	cont->mesg.p = malloc (length_buf);
	if (!cont->mesg.p)
		return (response_abort (cont, -1));

	cont->mesg_len = length_buf;
	cont->wp = cont->mesg.p;

	/* go next state */
	cont->process = tcp_response_reading_process;
	cont->retry = tcp_response_reading_retry;

	/* SUCCESS */
	return 0;
}
示例#3
0
int tcp_response_recursive_process (Context *cont) {
	const char *fn = "tcp_response_recursive_process()";

	syslog (LOG_DEBUG, "%s: start", fn);

	switch (recursive_process (cont)) {
	case 0:
		syslog (LOG_DEBUG, "%s: return, continue", fn);

		/* SUCCESS */
		return 0;
	case 1:
		assemble_response (cont);

		if (cont->mesg_len < 0 || cont->mesg_len > MAX_STREAM) {
			syslog (LOG_WARNING, "response message too big");
			return (response_abort (cont, 1));
		}

		if (cont->tout)
			cont->tout->handler = NULL;

		if (context_timeout_register (cont, cont->timeout))
			return (response_abort (cont, -1));

		/* register output */
		if (ev_tcp_out_register (cont->conn_sock, cont))
			return (response_abort (cont, -1));

		/* change the state */
		cont->process = tcp_response_writing_process;
		cont->retry = tcp_response_writing_retry;
		cont->wp = NULL;

		syslog (LOG_DEBUG, "%s: return, finish", fn);

		/* SUCCESS */
		return 0;
	default:
		return (response_abort (cont, -1));
	}
}
/*
 * When a new query is received over a UDP socket from a client, the
 * udp_response state machine is started. See also ev_udp_in_read(),
 * which is the only place from where udp_response_start() is called.
 *
 * udp_response_start() starts a new transaction. First creates a new
 * root context for it, and starts the forwarding of the original query.
 *
 *	forwarding is performed by starting a new child request, which
 *	if all goes well result in some resource records in our context.
 *
 * when the forwarded request finished successfully, udp_response_finish()
 * is responsible for interpreting it and sending a response back to the client.
 *
 */
int udp_response_start (u_char *mesg_buf, int mesg_len, struct sockaddr *sa_p,
			Nia *inif) {
	const char *fn = "udp_response_start()";
	Context *cont;

	syslog (LOG_DEBUG, "%s: start", fn);

	/* create context */
	cont = context_create();
	if (!cont)
		return (response_abort (cont, -1));

	cont->mesg.p = mesg_buf;
	cont->mesg_len = mesg_len;
	cont->wp = mesg_buf + mesg_len;	/* just after the answer section */
	cont->q_id = cont->mesg.hdr->id;
	cont->netifaddr = nia_copy (inif);
	memcpy (cont->peer, sa_p, SOCKADDR_SIZEOF(*sa_p));

	if (cont->mesg.hdr->opcode == OP_QUERY) {
		syslog (LOG_DEBUG, "%s: OPCODE = OP_QUERY", fn);

		/* query-response specific variables */
		cont->process = udp_response_recursive_process;
		cont->retry = udp_response_recursive_retry;

		/* do the forwarding, send request to forwarder */
		switch (request_start (cont, QUERY_TCP)) {
		case 0:
			/* We got a response */
			return (0);
		case 1:
			/* Something wrong with the query */
			cont->mesg.hdr->rcode = RC_FMTERR;
			return (udp_response_finish (cont));
		default:
			/* We failed ourselves somehow */
			cont->mesg.hdr->rcode = RC_SERVERERR;
			return (udp_response_finish (cont));
		}
	} else {
		syslog (LOG_NOTICE, "%s: OPCODE unknown(%d)", fn,
			cont->mesg.hdr->opcode);
		cont->mesg.hdr->rcode = RC_NIMP;
		return udp_response_finish (cont);
	}

	/* NOTREACHED */
	return 0;
}
示例#5
0
int tcp_response_start (int sock, struct sockaddr *sa_p) {
	const char *fn = "tcp_response_start()";
	Context *cont;

	syslog (LOG_DEBUG, "%s: start", fn);

	cont = context_create();
	if (!cont)
		return (response_abort (cont, -1));

	cont->process = tcp_response_readlen_process;
	cont->retry = tcp_response_readlen_retry;
	memcpy (cont->peer, sa_p, SOCKADDR_SIZEOF(*sa_p));

	cont->conn_sock = sock;
	cont->timeout = TCP_SRV_TIMEOUT;

	if (!context_timeout_register (cont, cont->timeout) &&
	    !ev_tcp_conn_in_register (cont->conn_sock, cont))
			return 0; /* SUCCESS */

	return (response_abort (cont, -1));
}
示例#6
0
int tcp_response_writing_process (Context *cont) {
	const char *fn = "tcp_response_writing_process()";

	syslog (LOG_DEBUG, "%s: start", fn);

	/* renew timeout */
	if (cont->tout)
		cont->tout->handler = NULL;

	if (context_timeout_register (cont, cont->timeout))
		return (response_abort (cont, -1));

	switch (tcp_writemesg (cont, cont->conn_sock)) {
	case 0:
		/* continue this process */
		syslog (LOG_DEBUG, "%s: return, continue", fn);

		/* SUCCESS */
		return 0;
	case 1:
		/* all data written */
		cont->process = tcp_response_waiting_client_close_process;
		cont->retry = tcp_response_waiting_client_close_retry;

		/* stop output and waiting for input */
		ev_tcp_out_remove (cont->conn_sock);
		ev_tcp_conn_in_register (cont->conn_sock, cont);

		syslog (LOG_DEBUG, "%s: return, finish", fn);

		/* SUCCESS */
		return 0;
	default:
		/* FAILURE */
		return (response_abort (cont, -1));
	}
}
int udp_response_recursive_retry (Context *cont) {
	syslog (LOG_ERR, "udp_response_recursive_retry should not be called.");
	return response_abort (cont, 0);
}
int udp_response_finish (Context *cont) {
        const char *fn = "udp_response_finish()";
	int len;

	syslog (LOG_DEBUG, "%s: start", fn);

	/*
	 * We trim the response down if it doesn't fit in a default UDP
	 * data in a somewhat crude way. Could be smarter, like trim
	 * A records from response for pure IPv6 queries and so. See, if
	 * it is needed often. Maybe better to support EDNS0 option instead.
	 *
	 * RFC1035 says we should truncate the message to 512 bytes and set the
	 * tr bit in the header, but it is really vague on when a response does
	 * not fit. RFC2181 clarifies the use of the tr bit in section 9.
	 *
	 * Note that similar logic is still present in mesg_assemble() in
	 * ne_mesg.c (may disappear if we add the logic to assemble_response()
	 * instead).
	 */
	assemble_response (cont);
	if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) {
		/* put the message on a diet */
		list_destroy (cont->ar_list, rrset_freev);
		cont->ar_list = NULL;
		syslog (LOG_DEBUG, "Overweight, dropping additional section");
		assemble_response (cont);
	}
	if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) {
		/*
		 * ok, water adn bread then then. shuold check
		 * RFCs, it may be better to return error msg
		 * instead of slimmed answer.
		 */
		list_destroy (cont->ns_list, rrset_freev);
		cont->ns_list = NULL;
		syslog (LOG_DEBUG, "Overweight, dropping authority section");
		assemble_response (cont);
	}
	if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) {
		/* ok, nothing viable left, so die */
		list_destroy (cont->an_list, rrset_freev);
		cont->an_list = NULL;
		assemble_response (cont);
		cont->mesg.hdr->tc = 1;
		syslog (LOG_WARNING, "Obese, answers too big for UDP");
	}
	if (cont->mesg_len < 0 || cont->mesg_len > MAX_PACKET) {
		syslog (LOG_ERR, "Even error msg is too big for UDP");
		return (response_abort (cont, 1));
	}

	/* send the answer */
	len = net_mesg_send (cont->netifaddr, cont->mesg.p, cont->mesg_len,
			     cont->peer);

	if (len < cont->mesg_len) {
		syslog (LOG_NOTICE, "failed to send message.");
		return (response_abort (cont, -1));
	}

        context_destroy (cont);
	return 0;
}
示例#9
0
int tcp_response_reading_process (Context *cont) {
	const char *fn = "tcp_response_reading_process()";
	int len;

	syslog (LOG_DEBUG, "%s: start", fn);

	if (cont->tout)
		cont->tout->handler = NULL;

	if (context_timeout_register (cont, cont->timeout))
		return(response_abort (cont, -1));

	len = read (cont->conn_sock, cont->wp,
		    cont->mesg_len - (cont->wp - cont->mesg.p));

	if (len <= 0)
		return(response_abort (cont, -1));

	cont->wp += len;
	if (cont->wp < (cont->mesg.p + cont->mesg_len)) {
		syslog (LOG_DEBUG, "%s: left %zd bytes -- continue.", fn,
			(cont->mesg.p + cont->mesg_len) - cont->wp);

		/* SUCCESS */
		return 0;	/* the processing continues ... */
	}

	/* all data has been read now */
	ev_tcp_conn_in_remove (cont->conn_sock);

	if (cont->mesg.hdr->opcode == OP_QUERY) {
		if (cont->tout)
			cont->tout->handler = NULL;

		/*
		 * don't register input list,
		 * child context takes input
		 */

		switch (request_start (cont, QUERY_TCP)) {
		case 0:
			/*
			 * We forwarded the request without problems,
			 * asycnhronously awaiting a response.
			 * goto recursive_processing state
			 * clear events, child will call me then
			 */
			if (cont->tout)
				cont->tout->handler = NULL;

			cont->process = tcp_response_recursive_process;
			cont->retry = tcp_response_recursive_retry;

			/* SUCCESS */
			return 0;
		case 1:
			/* Something wrong with the query */
			syslog (LOG_NOTICE, "%s: Request failed", fn);
			cont->mesg.hdr->rcode = RC_FMTERR;
		default:
			/* totd failed itself somehow */
			syslog (LOG_NOTICE, "%s: Totd failed", fn);
			cont->mesg.hdr->rcode = RC_SERVERERR;
		}
	} else
		cont->mesg.hdr->rcode = RC_NIMP;

	/* 
	 * Not OP_QUERY or Request failed brings us here
	 *
	 * Go to writing state. Timeout already done in this function
	 * Register new output event 
	 */

	if (!ev_tcp_out_register (cont->conn_sock, cont)) {
		assemble_response (cont);

		/* state change */
		cont->process = tcp_response_writing_process;
		cont->retry = tcp_response_writing_retry;
		cont->wp = NULL;

		syslog (LOG_DEBUG, "%s: end (writing:)", fn);
		/* SUCCESS */
		return 0;
	}

	/* FAILURE */
	return (response_abort (cont, -1));
}
示例#10
0
int tcp_response_readlen_retry (Context *cont) {
	const char *fn = "tcp_response_readlen_retry()";

	syslog (LOG_NOTICE, "%s: connection does not respond. closing.", fn);
	return (response_abort (cont, -1));
}
示例#11
0
int tcp_response_waiting_client_close_retry (Context *cont) {
	return (response_abort (cont, 0));
}
示例#12
0
int tcp_response_writing_retry (Context *cont) {
	return (response_abort (cont, -1));
}
示例#13
0
int tcp_response_recursive_retry (Context *cont) {
	return (response_abort (cont, -1));
}