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; }
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, struct regional* region, uint16_t udpsize, int dnssec) { uint16_t ancount=0, nscount=0, arcount=0; struct compress_tree_node* tree = 0; int r; size_t rr_offset; ldns_buffer_clear(buffer); if(udpsize < ldns_buffer_limit(buffer)) ldns_buffer_set_limit(buffer, udpsize); if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) return 0; ldns_buffer_write(buffer, &id, sizeof(uint16_t)); ldns_buffer_write_u16(buffer, flags); ldns_buffer_write_u16(buffer, rep->qdcount); /* set an, ns, ar counts to zero in case of small packets */ ldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); /* insert query section */ if(rep->qdcount) { if((r=insert_query(qinfo, &tree, buffer, region)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 4, 0); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } } /* roundrobin offset. using query id for random number */ rr_offset = RRSET_ROUNDROBIN?id:0; /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 6, ancount); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 6, ancount); /* if response is positive answer, auth/add sections are not required */ if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) { /* insert auth section */ if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, rep->an_numrrsets, timenow, region, &tree, LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 8, nscount); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 8, nscount); /* insert add section */ if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, rep->an_numrrsets + rep->ns_numrrsets, timenow, region, &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* no need to set TC bit, this is the additional */ ldns_buffer_write_u16_at(buffer, 10, arcount); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 10, arcount); } else { ldns_buffer_write_u16_at(buffer, 8, nscount); ldns_buffer_write_u16_at(buffer, 10, arcount); } ldns_buffer_flip(buffer); return 1; }