/** encode answer consisting of 1 rrset */ static int local_encode(struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec, int rcode) { struct reply_info rep; uint16_t udpsize; /* make answer with time=0 for fixed TTL values */ memset(&rep, 0, sizeof(rep)); rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode); rep.qdcount = 1; if(ansec) rep.an_numrrsets = 1; else rep.ns_numrrsets = 1; rep.rrset_count = 1; rep.rrsets = &rrset; udpsize = edns->udp_size; edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; if(!edns_opt_inplace_reply(edns, temp) || !reply_info_answer_encode(qinfo, &rep, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); return 1; }
/** * answer in case where no exact match is found * @param z: zone for query * @param qinfo: query * @param edns: edns from query * @param buf: buffer for answer. * @param temp: temp region for encoding * @param ld: local data, if NULL, no such name exists in localdata. * @param lz_type: type of the local zone * @return 1 if a reply is to be sent, 0 if not. */ static int lz_zone_answer(struct local_zone* z, struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, struct regional* temp, struct local_data* ld, enum localzone_type lz_type) { if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) { /** no reply at all, signal caller by clearing buffer. */ sldns_buffer_clear(buf); sldns_buffer_flip(buf); return 1; } else if(lz_type == local_zone_refuse || lz_type == local_zone_always_refuse) { error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); return 1; } else if(lz_type == local_zone_static || lz_type == local_zone_redirect || lz_type == local_zone_always_nxdomain) { /* for static, reply nodata or nxdomain * for redirect, reply nodata */ /* no additional section processing, * cname, dname or wildcard processing, * or using closest match for NSEC. * or using closest match for returning delegation downwards */ int rcode = (ld || lz_type == local_zone_redirect)? LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN; if(z->soa) return local_encode(qinfo, edns, buf, temp, z->soa, 0, rcode); error_encode(buf, (rcode|BIT_AA), qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); return 1; } else if(lz_type == local_zone_typetransparent || lz_type == local_zone_always_transparent) { /* no NODATA or NXDOMAINS for this zone type */ return 0; } /* else lz_type == local_zone_transparent */ /* if the zone is transparent and the name exists, but the type * does not, then we should make this noerror/nodata */ if(ld && ld->rrsets) { int rcode = LDNS_RCODE_NOERROR; if(z->soa) return local_encode(qinfo, edns, buf, temp, z->soa, 0, rcode); error_encode(buf, (rcode|BIT_AA), qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); return 1; } /* stop here, and resolve further on */ return 0; }
void attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) { size_t len; size_t rdatapos; struct edns_option* opt; if(!edns || !edns->edns_present) return; /* inc additional count */ sldns_buffer_write_u16_at(pkt, 10, sldns_buffer_read_u16_at(pkt, 10) + 1); len = sldns_buffer_limit(pkt); sldns_buffer_clear(pkt); sldns_buffer_set_position(pkt, len); /* write EDNS record */ sldns_buffer_write_u8(pkt, 0); /* '.' label */ sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ sldns_buffer_write_u16(pkt, edns->udp_size); /* class */ sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ sldns_buffer_write_u8(pkt, edns->edns_version); sldns_buffer_write_u16(pkt, edns->bits); rdatapos = sldns_buffer_position(pkt); sldns_buffer_write_u16(pkt, 0); /* rdatalen */ /* write rdata */ for(opt=edns->opt_list; opt; opt=opt->next) { sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) sldns_buffer_write(pkt, opt->opt_data, opt->opt_len); } if(edns->opt_list) sldns_buffer_write_u16_at(pkt, rdatapos, sldns_buffer_position(pkt)-rdatapos-2); sldns_buffer_flip(pkt); }
void dt_msg_send_outside_query(dt_env_t *env, struct sockaddr_storage *rsock, enum comm_point_type cptype, uint8_t *zone, size_t zone_len, sldns_buffer *qmsg) { dt_msg_t dm; struct timeval qtime; uint16_t qflags; gettimeofday(&qtime, NULL); qflags = sldns_buffer_read_u16_at(qmsg, 2); /* type */ if (qflags & BIT_RD) { if (!env->log_forwarder_query_messages) return; dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__FORWARDER_QUERY); } else { if (!env->log_resolver_query_messages) return; dt_msg_init(env, &dm, DNSTAP__MESSAGE__TYPE__RESOLVER_QUERY); } /* query_zone */ dm.m.query_zone.data = zone; dm.m.query_zone.len = zone_len; dm.m.has_query_zone = 1; /* query_time_sec, query_time_nsec */ dt_fill_timeval(&qtime, &dm.m.query_time_sec, &dm.m.has_query_time_sec, &dm.m.query_time_nsec, &dm.m.has_query_time_nsec); /* query_message */ dt_fill_buffer(qmsg, &dm.m.query_message, &dm.m.has_query_message); /* socket_family, socket_protocol, response_address, response_port */ log_assert(cptype == comm_udp || cptype == comm_tcp); dt_msg_fill_net(&dm, rsock, cptype, &dm.m.response_address, &dm.m.has_response_address, &dm.m.response_port, &dm.m.has_response_port); if (dt_pack(&dm.d, &dm.buf, &dm.len_buf)) dt_send(env, dm.buf, dm.len_buf); }
void attach_edns_record(sldns_buffer* pkt, struct edns_data* edns) { size_t len; if(!edns || !edns->edns_present) return; /* inc additional count */ sldns_buffer_write_u16_at(pkt, 10, sldns_buffer_read_u16_at(pkt, 10) + 1); len = sldns_buffer_limit(pkt); sldns_buffer_clear(pkt); sldns_buffer_set_position(pkt, len); /* write EDNS record */ sldns_buffer_write_u8(pkt, 0); /* '.' label */ sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ sldns_buffer_write_u16(pkt, edns->udp_size); /* class */ sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ sldns_buffer_write_u8(pkt, edns->edns_version); sldns_buffer_write_u16(pkt, edns->bits); sldns_buffer_write_u16(pkt, 0); /* rdatalen */ sldns_buffer_flip(pkt); }
void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c, uint16_t qtype, uint16_t qclass, struct edns_data* edns, struct comm_reply* repinfo) { uint16_t flags = sldns_buffer_read_u16_at(c->buffer, 2); if(qtype < UB_STATS_QTYPE_NUM) stats->qtype[qtype]++; else stats->qtype_big++; if(qclass < UB_STATS_QCLASS_NUM) stats->qclass[qclass]++; else stats->qclass_big++; stats->qopcode[ LDNS_OPCODE_WIRE(sldns_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++; } }
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; }