Esempio n. 1
0
void
attach_edns_record(ldns_buffer* pkt, struct edns_data* edns)
{
	size_t len;
	if(!edns || !edns->edns_present)
		return;
	/* inc additional count */
	ldns_buffer_write_u16_at(pkt, 10,
		ldns_buffer_read_u16_at(pkt, 10) + 1);
	len = ldns_buffer_limit(pkt);
	ldns_buffer_clear(pkt);
	ldns_buffer_set_position(pkt, len);
	/* write EDNS record */
	ldns_buffer_write_u8(pkt, 0); /* '.' label */
	ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
	ldns_buffer_write_u16(pkt, edns->udp_size); /* class */
	ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
	ldns_buffer_write_u8(pkt, edns->edns_version);
	ldns_buffer_write_u16(pkt, edns->bits);
	ldns_buffer_write_u16(pkt, 0); /* rdatalen */
	ldns_buffer_flip(pkt);
}
Esempio n. 2
0
void server_stats_insquery(struct server_stats* stats, struct comm_point* c,
	uint16_t qtype, uint16_t qclass, struct edns_data* edns,
	struct comm_reply* repinfo)
{
	uint16_t flags = ldns_buffer_read_u16_at(c->buffer, 2);
	if(qtype < STATS_QTYPE_NUM)
		stats->qtype[qtype]++;
	else	stats->qtype_big++;
	if(qclass < STATS_QCLASS_NUM)
		stats->qclass[qclass]++;
	else	stats->qclass_big++;
	stats->qopcode[ LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) ]++;
	if(c->type != comm_udp)
		stats->qtcp++;
	if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
		stats->qipv6++;
	if( (flags&BIT_QR) )
		stats->qbit_QR++;
	if( (flags&BIT_AA) )
		stats->qbit_AA++;
	if( (flags&BIT_TC) )
		stats->qbit_TC++;
	if( (flags&BIT_RD) )
		stats->qbit_RD++;
	if( (flags&BIT_RA) )
		stats->qbit_RA++;
	if( (flags&BIT_Z) )
		stats->qbit_Z++;
	if( (flags&BIT_AD) )
		stats->qbit_AD++;
	if( (flags&BIT_CD) )
		stats->qbit_CD++;
	if(edns->edns_present) {
		stats->qEDNS++;
		if( (edns->bits & EDNS_DO) )
			stats->qEDNS_DO++;
	}
}
Esempio n. 3
0
/**
 * Send reply to mesh reply entry
 * @param m: mesh state to send it for.
 * @param rcode: if not 0, error code.
 * @param rep: reply to send (or NULL if rcode is set).
 * @param r: reply entry
 * @param prev: previous reply, already has its answer encoded in buffer.
 */
static void
mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
	struct mesh_reply* r, struct mesh_reply* prev)
{
	struct timeval end_time;
	struct timeval duration;
	int secure;
	/* examine security status */
	if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
		m->s.env->cfg->ignore_cd) && rep && 
		rep->security <= sec_status_bogus) {
		rcode = LDNS_RCODE_SERVFAIL;
		if(m->s.env->cfg->stat_extended) 
			m->s.env->mesh->ans_bogus++;
	}
	if(rep && rep->security == sec_status_secure)
		secure = 1;
	else	secure = 0;
	if(!rep && rcode == LDNS_RCODE_NOERROR)
		rcode = LDNS_RCODE_SERVFAIL;
	/* send the reply */
	if(prev && prev->qflags == r->qflags && 
		prev->edns.edns_present == r->edns.edns_present && 
		prev->edns.bits == r->edns.bits && 
		prev->edns.udp_size == r->edns.udp_size) {
		/* if the previous reply is identical to this one, fix ID */
		if(prev->query_reply.c->buffer != r->query_reply.c->buffer)
			ldns_buffer_copy(r->query_reply.c->buffer, 
				prev->query_reply.c->buffer);
		ldns_buffer_write_at(r->query_reply.c->buffer, 0, 
			&r->qid, sizeof(uint16_t));
		ldns_buffer_write_at(r->query_reply.c->buffer, 12, 
			r->qname, m->s.qinfo.qname_len);
		comm_point_send_reply(&r->query_reply);
	} else if(rcode) {
		m->s.qinfo.qname = r->qname;
		error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
			r->qid, r->qflags, &r->edns);
		comm_point_send_reply(&r->query_reply);
	} else {
		size_t udp_size = r->edns.udp_size;
		r->edns.edns_version = EDNS_ADVERTISED_VERSION;
		r->edns.udp_size = EDNS_ADVERTISED_SIZE;
		r->edns.ext_rcode = 0;
		r->edns.bits &= EDNS_DO;
		m->s.qinfo.qname = r->qname;
		if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid, 
			r->qflags, r->query_reply.c->buffer, 0, 1, 
			m->s.env->scratch, udp_size, &r->edns, 
			(int)(r->edns.bits & EDNS_DO), secure)) 
		{
			error_encode(r->query_reply.c->buffer, 
				LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, 
				r->qflags, &r->edns);
		}
		comm_point_send_reply(&r->query_reply);
	}
	/* account */
	m->s.env->mesh->num_reply_addrs--;
	end_time = *m->s.env->now_tv;
	timeval_subtract(&duration, &end_time, &r->start_time);
	verbose(VERB_ALGO, "query took %d.%6.6d sec",
		(int)duration.tv_sec, (int)duration.tv_usec);
	m->s.env->mesh->replies_sent++;
	timeval_add(&m->s.env->mesh->replies_sum_wait, &duration);
	timehist_insert(m->s.env->mesh->histogram, &duration);
	if(m->s.env->cfg->stat_extended) {
		uint16_t rc = FLAGS_GET_RCODE(ldns_buffer_read_u16_at(r->
			query_reply.c->buffer, 2));
		if(secure) m->s.env->mesh->ans_secure++;
		m->s.env->mesh->ans_rcode[ rc ] ++;
		if(rc == 0 && LDNS_ANCOUNT(ldns_buffer_begin(r->
			query_reply.c->buffer)) == 0)
			m->s.env->mesh->ans_nodata++;
	}
}
Esempio n. 4
0
int 
worker_handle_request(struct comm_point* c, void* arg, int error,
	struct comm_reply* repinfo)
{
	struct worker* worker = (struct worker*)arg;
	int ret;
	hashvalue_t h;
	struct lruhash_entry* e;
	struct query_info qinfo;
	struct edns_data edns;
	enum acl_access acl;

	if(error != NETEVENT_NOERROR) {
		/* some bad tcp query DNS formats give these error calls */
		verbose(VERB_ALGO, "handle request called with err=%d", error);
		return 0;
	}
	acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, 
		repinfo->addrlen);
	if(acl == acl_deny) {
		comm_point_drop_reply(repinfo);
		if(worker->stats.extended)
			worker->stats.unwanted_queries++;
		return 0;
	} else if(acl == acl_refuse) {
		log_addr(VERB_ALGO, "refused query from",
			&repinfo->addr, repinfo->addrlen);
		log_buf(VERB_ALGO, "refuse", c->buffer);
		if(worker->stats.extended)
			worker->stats.unwanted_queries++;
		if(worker_check_request(c->buffer, worker) == -1) {
			comm_point_drop_reply(repinfo);
			return 0; /* discard this */
		}
		ldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
		ldns_buffer_write_at(c->buffer, 4, 
			(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
		LDNS_QR_SET(ldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), 
			LDNS_RCODE_REFUSED);
		return 1;
	}
	if((ret=worker_check_request(c->buffer, worker)) != 0) {
		verbose(VERB_ALGO, "worker check request: bad query.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		if(ret != -1) {
			LDNS_QR_SET(ldns_buffer_begin(c->buffer));
			LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
			return 1;
		}
		comm_point_drop_reply(repinfo);
		return 0;
	}
	worker->stats.num_queries++;
	/* see if query is in the cache */
	if(!query_info_parse(&qinfo, c->buffer)) {
		verbose(VERB_ALGO, "worker parse request: formerror.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		ldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(ldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), 
			LDNS_RCODE_FORMERR);
		server_stats_insrcode(&worker->stats, c->buffer);
		return 1;
	}
	if(worker->env.cfg->log_queries) {
		char ip[128];
		addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
		log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
	}
	if(qinfo.qtype == LDNS_RR_TYPE_AXFR || 
		qinfo.qtype == LDNS_RR_TYPE_IXFR) {
		verbose(VERB_ALGO, "worker request: refused zone transfer.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		ldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(ldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), 
			LDNS_RCODE_REFUSED);
		if(worker->stats.extended) {
			worker->stats.qtype[qinfo.qtype]++;
			server_stats_insrcode(&worker->stats, c->buffer);
		}
		return 1;
	}
	if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
		verbose(VERB_ALGO, "worker parse edns: formerror.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		ldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(ldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
		server_stats_insrcode(&worker->stats, c->buffer);
		return 1;
	}
	if(edns.edns_present && edns.edns_version != 0) {
		edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
		edns.edns_version = EDNS_ADVERTISED_VERSION;
		edns.udp_size = EDNS_ADVERTISED_SIZE;
		edns.bits &= EDNS_DO;
		verbose(VERB_ALGO, "query with bad edns version.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
			*(uint16_t*)ldns_buffer_begin(c->buffer),
			ldns_buffer_read_u16_at(c->buffer, 2), NULL);
		attach_edns_record(c->buffer, &edns);
		return 1;
	}