예제 #1
0
/*
 * Answer if this is an AXFR or IXFR query.
 */
query_state_type
answer_axfr_ixfr(struct nsd *nsd, struct query *q)
{
	struct acl_options *acl = NULL;
	/* Is it AXFR? */
	switch (q->qtype) {
	case TYPE_AXFR:
		if (q->tcp) {
			struct zone_options* zone_opt;
			zone_opt = zone_options_find(nsd->options, q->qname);
			if(!zone_opt ||
			   acl_check_incoming(zone_opt->pattern->provide_xfr, q, &acl)==-1)
			{
				if (verbosity >= 2) {
					char a[128];
					addr2str(&q->addr, a, sizeof(a));
					VERBOSITY(2, (LOG_INFO, "axfr for %s from %s refused, %s",
						dname_to_string(q->qname, NULL), a, acl?"blocked":"no acl matches"));
				}
				DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s",
					acl?"blocked":"no acl matches"));
				if (!zone_opt) {
					RCODE_SET(q->packet, RCODE_NOTAUTH);
				} else {
					RCODE_SET(q->packet, RCODE_REFUSE);
				}
				return QUERY_PROCESSED;
			}
			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s",
				acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
			if (verbosity >= 1) {
				char a[128];
				addr2str(&q->addr, a, sizeof(a));
				VERBOSITY(1, (LOG_INFO, "%s for %s from %s",
					(q->qtype==TYPE_AXFR?"axfr":"ixfr"),
					dname_to_string(q->qname, NULL), a));
			}
			return query_axfr(nsd, q);
		}
		/** Fallthrough: AXFR over UDP queries are discarded. */
		/* fallthrough */
	case TYPE_IXFR:
		RCODE_SET(q->packet, RCODE_IMPL);
		return QUERY_PROCESSED;
	default:
		return QUERY_DISCARDED;
	}
}
예제 #2
0
/*
 * Answer if this is an AXFR or IXFR query.
 */
query_state_type
answer_axfr_ixfr(struct nsd *nsd, struct query *q)
{
	acl_options_t *acl;
	/* Is it AXFR? */
	switch (q->qtype) {
	case TYPE_AXFR:
		if (q->tcp) {
			zone_options_t* zone_opt;
			zone_opt = zone_options_find(nsd->options, q->qname);
			if(!zone_opt ||
			   acl_check_incoming(zone_opt->provide_xfr, q, &acl)==-1)
			{
				if (verbosity > 0) {
					char address[128];
					if (addr2ip(q->addr, address, sizeof(address))) {
						DEBUG(DEBUG_XFRD,1, (LOG_INFO,
							"addr2ip failed"));
						strlcpy(address, "[unknown]", sizeof(address));
					}
					VERBOSITY(1, (LOG_INFO, "axfr for zone %s from client %s refused, %s",
						dname_to_string(q->qname, NULL), address, acl?"blocked":"no acl matches"));
				}
				DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr refused, %s",
					acl?"blocked":"no acl matches"));
				if (!zone_opt) {
					RCODE_SET(q->packet, RCODE_NOTAUTH);
				} else {
					RCODE_SET(q->packet, RCODE_REFUSE);
				}
				return QUERY_PROCESSED;
			}
			DEBUG(DEBUG_XFRD,1, (LOG_INFO, "axfr admitted acl %s %s",
				acl->ip_address_spec, acl->key_name?acl->key_name:"NOKEY"));
			return query_axfr(nsd, q);
		}
	case TYPE_IXFR:
		RCODE_SET(q->packet, RCODE_IMPL);
		return QUERY_PROCESSED;
	default:
		return QUERY_DISCARDED;
	}
}
예제 #3
0
static void
handle_tcp_writing(netio_type *netio,
		   netio_handler_type *handler,
		   netio_event_types_type event_types)
{
	struct tcp_handler_data *data
		= (struct tcp_handler_data *) handler->user_data;
	ssize_t sent;
	struct query *q = data->query;

	if (event_types & NETIO_EVENT_TIMEOUT) {
		/* Connection timed out.  */
		cleanup_tcp_handler(netio, handler);
		return;
	}

	assert(event_types & NETIO_EVENT_WRITE);

	if (data->bytes_transmitted < sizeof(q->tcplen)) {
		/* Writing the response packet length.  */
		uint16_t n_tcplen = htons(q->tcplen);
		sent = write(handler->fd,
			     (const char *) &n_tcplen + data->bytes_transmitted,
			     sizeof(n_tcplen) - data->bytes_transmitted);
		if (sent == -1) {
			if (errno == EAGAIN || errno == EINTR) {
				/*
				 * Write would block, wait until
				 * socket becomes writable again.
				 */
				return;
			} else {
#ifdef ECONNRESET
				if(verbosity >= 2 || errno != ECONNRESET)
#endif /* ECONNRESET */
#ifdef EPIPE
					if(verbosity >= 2 || errno != EPIPE)
#endif /* EPIPE 'broken pipe' */
				log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno));
				cleanup_tcp_handler(netio, handler);
				return;
			}
		}

		data->bytes_transmitted += sent;
		if (data->bytes_transmitted < sizeof(q->tcplen)) {
			/*
			 * Writing not complete, wait until socket
			 * becomes writable again.
			 */
			return;
		}

		assert(data->bytes_transmitted == sizeof(q->tcplen));
	}

	assert(data->bytes_transmitted < q->tcplen + sizeof(q->tcplen));

	sent = write(handler->fd,
		     buffer_current(q->packet),
		     buffer_remaining(q->packet));
	if (sent == -1) {
		if (errno == EAGAIN || errno == EINTR) {
			/*
			 * Write would block, wait until
			 * socket becomes writable again.
			 */
			return;
		} else {
#ifdef ECONNRESET
			if(verbosity >= 2 || errno != ECONNRESET)
#endif /* ECONNRESET */
#ifdef EPIPE
					if(verbosity >= 2 || errno != EPIPE)
#endif /* EPIPE 'broken pipe' */
			log_msg(LOG_ERR, "failed writing to tcp: %s", strerror(errno));
			cleanup_tcp_handler(netio, handler);
			return;
		}
	}

	buffer_skip(q->packet, sent);
	data->bytes_transmitted += sent;
	if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) {
		/*
		 * Still more data to write when socket becomes
		 * writable again.
		 */
		return;
	}

	assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen));

	if (data->query_state == QUERY_IN_AXFR) {
		/* Continue processing AXFR and writing back results.  */
		buffer_clear(q->packet);
		data->query_state = query_axfr(data->nsd, q);
		if (data->query_state != QUERY_PROCESSED) {
			query_add_optional(data->query, data->nsd);

			/* Reset data. */
			buffer_flip(q->packet);
			q->tcplen = buffer_remaining(q->packet);
			data->bytes_transmitted = 0;
			/* Reset timeout.  */
			handler->timeout->tv_sec = data->nsd->tcp_timeout;
			handler->timeout->tv_nsec = 0;
			timespec_add(handler->timeout, netio_current_time(netio));

			/*
			 * Write data if/when the socket is writable
			 * again.
			 */
			return;
		}
	}

	/*
	 * Done sending, wait for the next request to arrive on the
	 * TCP socket by installing the TCP read handler.
	 */
	if (data->nsd->tcp_query_count > 0 &&
		data->query_count >= data->nsd->tcp_query_count) {

		(void) shutdown(handler->fd, SHUT_WR);
	}

	data->bytes_transmitted = 0;

	handler->timeout->tv_sec = data->nsd->tcp_timeout;
	handler->timeout->tv_nsec = 0;
	timespec_add(handler->timeout, netio_current_time(netio));

	handler->event_types = NETIO_EVENT_READ | NETIO_EVENT_TIMEOUT;
	handler->event_handler = handle_tcp_reading;
}