/** * Fill CH class answer into buffer. Keeps query. * @param pkt: buffer * @param str: string to put into text record (<255). * @param edns: edns reply information. * @param worker: worker with scratch region. */ static void chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns, struct worker* worker) { size_t len = strlen(str); unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); if(len>255) len=255; /* cap size of TXT record */ sldns_buffer_clear(pkt); sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); sldns_buffer_write_u16(pkt, 1); /* qdcount */ sldns_buffer_write_u16(pkt, 1); /* ancount */ sldns_buffer_write_u16(pkt, 0); /* nscount */ sldns_buffer_write_u16(pkt, 0); /* arcount */ (void)query_dname_len(pkt); /* skip qname */ sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); sldns_buffer_write_u32(pkt, 0); /* TTL */ sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); sldns_buffer_write_u8(pkt, len); sldns_buffer_write(pkt, str, len); sldns_buffer_flip(pkt); edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->bits &= EDNS_DO; if(!edns_opt_inplace_reply(edns, worker->scratchpad)) edns->opt_list = NULL; attach_edns_record(pkt, edns); }
/** performance test message encoding */ static void perf_encode(struct query_info* qi, struct reply_info* rep, uint16_t id, uint16_t flags, sldns_buffer* out, time_t timenow, struct edns_data* edns) { static int num = 0; int ret; size_t max = 10000; size_t i; struct timeval start, end; double dt; struct regional* r2 = regional_create(); if(gettimeofday(&start, NULL) < 0) fatal_exit("gettimeofday: %s", strerror(errno)); /* encode a couple times */ for(i=0; i<max; i++) { ret = reply_info_encode(qi, rep, id, flags, out, timenow, r2, 65535, (int)(edns->bits & EDNS_DO) ); unit_assert(ret != 0); /* udp packets should fit */ attach_edns_record(out, edns); regional_free_all(r2); } if(gettimeofday(&end, NULL) < 0) fatal_exit("gettimeofday: %s", strerror(errno)); /* time in millisec */ dt = (double)(end.tv_sec - start.tv_sec)*1000. + ((double)end.tv_usec - (double)start.tv_usec)/1000.; printf("[%d] did %u in %g msec for %f encode/sec size %d\n", num++, (unsigned)max, dt, (double)max / (dt/1000.), (int)sldns_buffer_limit(out)); regional_destroy(r2); }
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow, int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure) { uint16_t flags; unsigned int attach_edns = 0; if(!cached || rep->authoritative) { /* original flags, copy RD and CD bits from query. */ flags = rep->flags | (qflags & (BIT_RD|BIT_CD)); } else { /* remove AA bit, copy RD and CD bits from query. */ flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); } if(secure && (dnssec || (qflags&BIT_AD))) flags |= BIT_AD; /* restore AA bit if we have a local alias and the response can be * authoritative. Also clear AD bit if set as the local data is the * primary answer. */ if(qinf->local_alias && (FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR || FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN)) { flags |= BIT_AA; flags &= ~BIT_AD; } log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ if(udpsize < LDNS_HEADER_SIZE) return 0; if(sldns_buffer_capacity(pkt) < udpsize) udpsize = sldns_buffer_capacity(pkt); if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { /* reserve space for edns record */ attach_edns = (unsigned int)calc_edns_field_size(edns); udpsize -= attach_edns; } if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region, udpsize, dnssec)) { log_err("reply encode: out of memory"); return 0; } if(attach_edns && sldns_buffer_capacity(pkt) >= sldns_buffer_limit(pkt)+attach_edns) attach_edns_record(pkt, edns); return 1; }
void error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, uint16_t qid, uint16_t qflags, struct edns_data* edns) { uint16_t flags; sldns_buffer_clear(buf); sldns_buffer_write(buf, &qid, sizeof(uint16_t)); flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ sldns_buffer_write_u16(buf, flags); if(qinfo) flags = 1; else flags = 0; sldns_buffer_write_u16(buf, flags); flags = 0; sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { const uint8_t* qname = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname : qinfo->qname; size_t qname_len = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_current(buf) == qname) sldns_buffer_skip(buf, (ssize_t)qname_len); else sldns_buffer_write(buf, qname, qname_len); sldns_buffer_write_u16(buf, qinfo->qtype); sldns_buffer_write_u16(buf, qinfo->qclass); } sldns_buffer_flip(buf); if(edns) { struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = 0; es.bits &= EDNS_DO; if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > edns->udp_size) return; attach_edns_record(buf, &es); } }
/** parse a query line to a packet into buffer */ static int qlist_parse_line(sldns_buffer* buf, char* p) { char nm[1024], cl[1024], tp[1024], fl[1024]; int r; int rec = 1, edns = 0; struct query_info qinfo; nm[0] = 0; cl[0] = 0; tp[0] = 0; fl[0] = 0; r = sscanf(p, " %1023s %1023s %1023s %1023s", nm, cl, tp, fl); if(r != 3 && r != 4) return 0; /*printf("nm='%s', cl='%s', tp='%s', fl='%s'\n", nm, cl, tp, fl);*/ if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0) { qinfo.qtype = sldns_get_rr_type_by_name(cl); qinfo.qclass = sldns_get_rr_class_by_name(tp); } else { qinfo.qtype = sldns_get_rr_type_by_name(tp); qinfo.qclass = sldns_get_rr_class_by_name(cl); } if(fl[0] == '+') rec = 1; else if(fl[0] == '-') rec = 0; else if(fl[0] == 'E') edns = 1; if((fl[0] == '+' || fl[0] == '-') && fl[1] == 'E') edns = 1; qinfo.qname = sldns_str2wire_dname(nm, &qinfo.qname_len); if(!qinfo.qname) return 0; qinfo_query_encode(buf, &qinfo); sldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */ if(rec) LDNS_RD_SET(sldns_buffer_begin(buf)); if(edns) { struct edns_data ed; memset(&ed, 0, sizeof(ed)); ed.edns_present = 1; ed.udp_size = EDNS_ADVERTISED_SIZE; /* Set DO bit in all EDNS datagrams ... */ ed.bits = EDNS_DO; attach_edns_record(buf, &ed); } free(qinfo.qname); return 1; }
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow, int cached, struct regional* region, uint16_t udpsize, struct edns_data* edns, int dnssec, int secure) { uint16_t flags; int attach_edns = 1; if(!cached || rep->authoritative) { /* original flags, copy RD and CD bits from query. */ flags = rep->flags | (qflags & (BIT_RD|BIT_CD)); } else { /* remove AA bit, copy RD and CD bits from query. */ flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD)); } if(secure && (dnssec || (qflags&BIT_AD))) flags |= BIT_AD; log_assert(flags & BIT_QR); /* QR bit must be on in our replies */ if(udpsize < LDNS_HEADER_SIZE) return 0; if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { /* reserve space for edns record */ udpsize -= calc_edns_field_size(edns); } if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region, udpsize, dnssec)) { log_err("reply encode: out of memory"); return 0; } if(attach_edns) attach_edns_record(pkt, edns); return 1; }
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; }
/** test a packet */ static void testpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, const char* hex) { struct query_info qi; struct reply_info* rep = 0; int ret; uint16_t id; uint16_t flags; uint32_t timenow = 0; struct regional* region = regional_create(); struct edns_data edns; hex_to_buf(pkt, hex); memmove(&id, sldns_buffer_begin(pkt), sizeof(id)); if(sldns_buffer_limit(pkt) < 2) flags = 0; else memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags)); flags = ntohs(flags); ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns); if(ret != 0) { char rbuf[16]; sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf)); if(vbmp) printf("parse code %d: %s\n", ret, rbuf); if(ret == LDNS_RCODE_FORMERR) { unit_assert(!check_formerr_gone); checkformerr(pkt); } unit_assert(ret != LDNS_RCODE_SERVFAIL); } else if(!check_formerr_gone) { const size_t lim = 512; ret = reply_info_encode(&qi, rep, id, flags, out, timenow, region, 65535, (int)(edns.bits & EDNS_DO) ); unit_assert(ret != 0); /* udp packets should fit */ attach_edns_record(out, &edns); if(vbmp) printf("inlen %u outlen %u\n", (unsigned)sldns_buffer_limit(pkt), (unsigned)sldns_buffer_limit(out)); if(!check_nosameness) test_buffers(pkt, out); if(check_rrsigs) check_the_rrsigs(&qi, rep); if(sldns_buffer_limit(out) > lim) { ret = reply_info_encode(&qi, rep, id, flags, out, timenow, region, lim - calc_edns_field_size(&edns), (int)(edns.bits & EDNS_DO)); unit_assert(ret != 0); /* should fit, but with TC */ attach_edns_record(out, &edns); if( LDNS_QDCOUNT(sldns_buffer_begin(out)) != LDNS_QDCOUNT(sldns_buffer_begin(pkt)) || LDNS_ANCOUNT(sldns_buffer_begin(out)) != LDNS_ANCOUNT(sldns_buffer_begin(pkt)) || LDNS_NSCOUNT(sldns_buffer_begin(out)) != LDNS_NSCOUNT(sldns_buffer_begin(pkt))) unit_assert( LDNS_TC_WIRE(sldns_buffer_begin(out))); /* must set TC bit if shortened */ unit_assert(sldns_buffer_limit(out) <= lim); } } query_info_clear(&qi); reply_info_parsedelete(rep, alloc); regional_destroy(region); }
struct serviced_query* outnet_serviced_query(struct outside_network* outnet, uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, size_t zonelen, comm_point_callback_t* callback, void* callback_arg, sldns_buffer* ATTR_UNUSED(buff)) { struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; struct fake_pending* pend = (struct fake_pending*)calloc(1, sizeof(struct fake_pending)); char z[256]; log_assert(pend); log_nametypeclass(VERB_OPS, "pending serviced query", qname, qtype, qclass); dname_str(zone, z); verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s", z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"", (flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":""); /* create packet with EDNS */ pend->buffer = sldns_buffer_new(512); log_assert(pend->buffer); sldns_buffer_write_u16(pend->buffer, 0); /* id */ sldns_buffer_write_u16(pend->buffer, flags); sldns_buffer_write_u16(pend->buffer, 1); /* qdcount */ sldns_buffer_write_u16(pend->buffer, 0); /* ancount */ sldns_buffer_write_u16(pend->buffer, 0); /* nscount */ sldns_buffer_write_u16(pend->buffer, 0); /* arcount */ sldns_buffer_write(pend->buffer, qname, qnamelen); sldns_buffer_write_u16(pend->buffer, qtype); sldns_buffer_write_u16(pend->buffer, qclass); sldns_buffer_flip(pend->buffer); if(1) { /* add edns */ struct edns_data edns; edns.edns_present = 1; edns.ext_rcode = 0; edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits = 0; if(dnssec) edns.bits = EDNS_DO; attach_edns_record(pend->buffer, &edns); } memcpy(&pend->addr, addr, addrlen); pend->addrlen = addrlen; pend->zone = memdup(zone, zonelen); pend->zonelen = zonelen; pend->qtype = (int)qtype; log_assert(pend->zone); pend->callback = callback; pend->cb_arg = callback_arg; pend->timeout = UDP_AUTH_QUERY_TIMEOUT; pend->transport = transport_udp; /* pretend UDP */ pend->pkt = NULL; pend->runtime = runtime; pend->serviced = 1; pend->pkt_len = sldns_buffer_limit(pend->buffer); pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len); if(!pend->pkt) fatal_exit("out of memory"); /*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/ /* see if it matches the current moment */ if(runtime->now && runtime->now->evt_type == repevt_back_query && (runtime->now->addrlen == 0 || sockaddr_cmp( &runtime->now->addr, runtime->now->addrlen, &pend->addr, pend->addrlen) == 0) && find_match(runtime->now->match, pend->pkt, pend->pkt_len, pend->transport)) { log_info("testbound: matched pending to event. " "advance time between events."); log_info("testbound: do STEP %d %s", runtime->now->time_step, repevt_string(runtime->now->evt_type)); advance_moment(runtime); /* still create the pending, because we need it to callback */ } log_info("testbound: created fake pending"); /* add to list */ pend->next = runtime->pending_list; runtime->pending_list = pend; return (struct serviced_query*)pend; }
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; }
/** write a query over the TCP fd */ static void write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, const char* strname, const char* strtype, const char* strclass) { struct query_info qinfo; uint16_t len; /* qname */ qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); if(!qinfo.qname) { printf("cannot parse query name: '%s'\n", strname); exit(1); } /* qtype and qclass */ qinfo.qtype = sldns_get_rr_type_by_name(strtype); qinfo.qclass = sldns_get_rr_class_by_name(strclass); /* make query */ qinfo_query_encode(buf, &qinfo); sldns_buffer_write_u16_at(buf, 0, id); sldns_buffer_write_u16_at(buf, 2, BIT_RD); if(1) { /* add EDNS DO */ struct edns_data edns; memset(&edns, 0, sizeof(edns)); edns.edns_present = 1; edns.bits = EDNS_DO; edns.udp_size = 4096; attach_edns_record(buf, &edns); } /* send it */ if(!udp) { len = (uint16_t)sldns_buffer_limit(buf); len = htons(len); if(ssl) { if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) { log_crypto_err("cannot SSL_write"); exit(1); } } else { if(send(fd, (void*)&len, sizeof(len), 0) < (ssize_t)sizeof(len)){ #ifndef USE_WINSOCK perror("send() len failed"); #else printf("send len: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } } if(ssl) { if(SSL_write(ssl, (void*)sldns_buffer_begin(buf), (int)sldns_buffer_limit(buf)) <= 0) { log_crypto_err("cannot SSL_write"); exit(1); } } else { if(send(fd, (void*)sldns_buffer_begin(buf), sldns_buffer_limit(buf), 0) < (ssize_t)sldns_buffer_limit(buf)) { #ifndef USE_WINSOCK perror("send() data failed"); #else printf("send data: %s\n", wsa_strerror(WSAGetLastError())); #endif exit(1); } } free(qinfo.qname); }