Beispiel #1
0
static int
deny_refuse(struct comm_point* c, enum acl_access acl,
	enum acl_access deny, enum acl_access refuse,
	struct worker* worker, struct comm_reply* repinfo)
{
	if(acl == deny) {
		comm_point_drop_reply(repinfo);
		if(worker->stats.extended)
			worker->stats.unwanted_queries++;
		return 0;
	} else if(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 */
		}
		sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
		sldns_buffer_write_at(c->buffer, 4, 
			(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
			LDNS_RCODE_REFUSED);
		return 1;
	}

	return -1;
}
Beispiel #2
0
void 
mesh_state_cleanup(struct mesh_state* mstate)
{
	struct mesh_area* mesh;
	int i;
	if(!mstate)
		return;
	mesh = mstate->s.env->mesh;
	/* drop unsent replies */
	if(!mstate->replies_sent) {
		struct mesh_reply* rep;
		struct mesh_cb* cb;
		for(rep=mstate->reply_list; rep; rep=rep->next) {
			comm_point_drop_reply(&rep->query_reply);
			mesh->num_reply_addrs--;
		}
		for(cb=mstate->cb_list; cb; cb=cb->next) {
			fptr_ok(fptr_whitelist_mesh_cb(cb->cb));
			(*cb->cb)(cb->cb_arg, LDNS_RCODE_SERVFAIL, NULL,
				sec_status_unchecked, NULL);
			mesh->num_reply_addrs--;
		}
	}

	/* de-init modules */
	for(i=0; i<mesh->mods.num; i++) {
		fptr_ok(fptr_whitelist_mod_clear(mesh->mods.mod[i]->clear));
		(*mesh->mods.mod[i]->clear)(&mstate->s, i);
		mstate->s.minfo[i] = NULL;
		mstate->s.ext_state[i] = module_finished;
	}
	alloc_reg_release(mstate->s.env->alloc, mstate->s.region);
}
Beispiel #3
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;
	int rc = 0;

	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;
	}
#ifdef USE_DNSTAP
	if(worker->dtenv.log_client_query_messages)
		dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type,
			c->buffer);
#endif
	acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, 
		repinfo->addrlen);
	if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1)
	{
		if(ret == 1)
			goto send_reply;
		return ret;
	}
	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(sldns_buffer_begin(c->buffer));
			LDNS_RCODE_SET(sldns_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);
		if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
			comm_point_drop_reply(repinfo);
			return 0;
		}
		sldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
			LDNS_RCODE_FORMERR);
		server_stats_insrcode(&worker->stats, c->buffer);
		goto send_reply;
	}
	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);
		sldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
			LDNS_RCODE_REFUSED);
		if(worker->stats.extended) {
			worker->stats.qtype[qinfo.qtype]++;
			server_stats_insrcode(&worker->stats, c->buffer);
		}
		goto send_reply;
	}
	if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) {
		struct edns_data reply_edns;
		verbose(VERB_ALGO, "worker parse edns: formerror.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		memset(&reply_edns, 0, sizeof(reply_edns));
		reply_edns.edns_present = 1;
		reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
		error_encode(c->buffer, ret, &qinfo,
			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
			sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
		regional_free_all(worker->scratchpad);
		server_stats_insrcode(&worker->stats, c->buffer);
		goto send_reply;
	}
	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;
		edns.opt_list = NULL;
		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*)(void *)sldns_buffer_begin(c->buffer),
			sldns_buffer_read_u16_at(c->buffer, 2), NULL);
		attach_edns_record(c->buffer, &edns);
		regional_free_all(worker->scratchpad);
		goto send_reply;
	}
Beispiel #4
0
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qflags, struct edns_data* edns, struct comm_reply* rep,
        uint16_t qid)
{
	/* do not use CD flag from user for mesh state, we want the CD-query
	 * to receive validation anyway, to protect out cache contents and
	 * avoid bad-data in this cache that a downstream validator cannot
	 * remove from this cache */
	struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags&BIT_RD, 0);
	int was_detached = 0;
	int was_noreply = 0;
	int added = 0;
	/* does this create a new reply state? */
	if(!s || s->list_select == mesh_no_list) {
		if(!mesh_make_new_space(mesh, rep->c->buffer)) {
			verbose(VERB_ALGO, "Too many queries. dropping "
				"incoming query.");
			comm_point_drop_reply(rep);
			mesh->stats_dropped ++;
			return;
		}
		/* for this new reply state, the reply address is free,
		 * so the limit of reply addresses does not stop reply states*/
	} else {
		/* protect our memory usage from storing reply addresses */
		if(mesh->num_reply_addrs > mesh->max_reply_states*16) {
			verbose(VERB_ALGO, "Too many requests queued. "
				"dropping incoming query.");
			mesh->stats_dropped++;
			comm_point_drop_reply(rep);
			return;
		}
	}
	/* see if it already exists, if not, create one */
	if(!s) {
#ifdef UNBOUND_DEBUG
		struct rbnode_t* n;
#endif
		s = mesh_state_create(mesh->env, qinfo, qflags&BIT_RD, 0);
		if(!s) {
			log_err("mesh_state_create: out of memory; SERVFAIL");
			error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
				qinfo, qid, qflags, edns);
			comm_point_send_reply(rep);
			return;
		}
#ifdef UNBOUND_DEBUG
		n =
#endif
		rbtree_insert(&mesh->all, &s->node);
		log_assert(n != NULL);
		/* set detached (it is now) */
		mesh->num_detached_states++;
		added = 1;
	}
	if(!s->reply_list && !s->cb_list && s->super_set.count == 0)
		was_detached = 1;
	if(!s->reply_list && !s->cb_list)
		was_noreply = 1;
	/* add reply to s */
	if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo->qname)) {
			log_err("mesh_new_client: out of memory; SERVFAIL");
			error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
				qinfo, qid, qflags, edns);
			comm_point_send_reply(rep);
			if(added)
				mesh_state_delete(&s->s);
			return;
	}
	/* update statistics */
	if(was_detached) {
		log_assert(mesh->num_detached_states > 0);
		mesh->num_detached_states--;
	}
	if(was_noreply) {
		mesh->num_reply_states ++;
	}
	mesh->num_reply_addrs++;
	if(s->list_select == mesh_no_list) {
		/* move to either the forever or the jostle_list */
		if(mesh->num_forever_states < mesh->max_forever_states) {
			mesh->num_forever_states ++;
			mesh_list_insert(s, &mesh->forever_first, 
				&mesh->forever_last);
			s->list_select = mesh_forever_list;
		} else {
			mesh_list_insert(s, &mesh->jostle_first, 
				&mesh->jostle_last);
			s->list_select = mesh_jostle_list;
		}
	}
	if(added)
		mesh_run(mesh, s, module_event_new, NULL);
}
Beispiel #5
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;
	}