void truncation_check(evldns_server_request *srq) { ldns_pkt *req = srq->request; ldns_pkt *resp = srq->response; unsigned int bufsize = 512; /* if it's TCP, business as usual */ if (srq->is_tcp) { return; } /* otherwise, convert to wire format, if necessary */ if (!srq->wire_response) { (void) ldns_pkt2wire(&srq->wire_response, resp, &srq->wire_resplen); } /* if it's under the RFC 1035 limit, we're OK */ if (srq->wire_resplen <= bufsize) { return; } /* if the client used EDNS, use that new bufsize */ if (ldns_pkt_edns(req)) { unsigned int ednssize = ldns_pkt_edns_udp_size(req); if (ednssize > bufsize) { bufsize = ednssize; } /* it fits - we're OK */ if (srq->wire_resplen <= bufsize) { return; } } /* * if we got here, it didn't fit - throw away the * existing wire buffer and the non-question sections */ free(srq->wire_response); LDNS_rr_list_empty_rr_list(ldns_pkt_additional(resp)); LDNS_rr_list_empty_rr_list(ldns_pkt_authority(resp)); LDNS_rr_list_empty_rr_list(ldns_pkt_answer(resp)); /* set the TC bit and reset section counts */ ldns_pkt_set_tc(resp, true); ldns_pkt_set_ancount(resp, 0); ldns_pkt_set_nscount(resp, 0); ldns_pkt_set_arcount(resp, 0); /* and convert to wire format again */ (void) ldns_pkt2wire(&srq->wire_response, resp, &srq->wire_resplen); }
/** Match q edns data to p raw edns data */ static int match_ednsdata(ldns_pkt* q, struct reply_packet* p) { size_t qdlen, pdlen; uint8_t *qd, *pd; if(!ldns_pkt_edns(q) || !ldns_pkt_edns_data(q)) { verbose(3, "No EDNS data\n"); return 0; } qdlen = ldns_rdf_size(ldns_pkt_edns_data(q)); pdlen = ldns_buffer_limit(p->raw_ednsdata); qd = ldns_rdf_data(ldns_pkt_edns_data(q)); pd = ldns_buffer_begin(p->raw_ednsdata); if( qdlen == pdlen && 0 == memcmp(qd, pd, qdlen) ) return 1; verbose(3, "EDNS data does not match.\n"); verbose_hex(3, qd, qdlen, "q:"); verbose_hex(3, pd, pdlen, "p:"); return 0; }
/* * Copies the packet header data to the buffer in wire format */ static ldns_status ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) { uint8_t flags; uint16_t arcount; if (ldns_buffer_reserve(buffer, 12)) { ldns_buffer_write_u16(buffer, ldns_pkt_id(packet)); flags = ldns_pkt_qr(packet) << 7 | ldns_pkt_get_opcode(packet) << 3 | ldns_pkt_aa(packet) << 2 | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet); ldns_buffer_write_u8(buffer, flags); flags = ldns_pkt_ra(packet) << 7 /*| ldns_pkt_z(packet) << 6*/ | ldns_pkt_ad(packet) << 5 | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet); ldns_buffer_write_u8(buffer, flags); ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet)); ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet)); ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet)); /* add EDNS0 and TSIG to additional if they are there */ arcount = ldns_pkt_arcount(packet); if (ldns_pkt_tsig(packet)) { arcount++; } if (ldns_pkt_edns(packet)) { arcount++; } ldns_buffer_write_u16(buffer, arcount); } return ldns_buffer_status(buffer); }
ldns_status ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) { ldns_rr_list *rr_list; uint16_t i; /* edns tmp vars */ ldns_rr *edns_rr; uint8_t edata[4]; (void) ldns_hdr2buffer_wire(buffer, packet); rr_list = ldns_pkt_question(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION); } } rr_list = ldns_pkt_answer(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER); } } rr_list = ldns_pkt_authority(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY); } } rr_list = ldns_pkt_additional(packet); if (rr_list) { for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { (void) ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL); } } /* add EDNS to additional if it is needed */ if (ldns_pkt_edns(packet)) { edns_rr = ldns_rr_new(); ldns_rr_set_owner(edns_rr, ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".")); ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT); ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet)); edata[0] = ldns_pkt_edns_extended_rcode(packet); edata[1] = ldns_pkt_edns_version(packet); ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet)); ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata)); (void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL); ldns_rr_free(edns_rr); } /* add TSIG to additional if it is there */ if (ldns_pkt_tsig(packet)) { (void) ldns_rr2buffer_wire(buffer, ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL); } return LDNS_STATUS_OK; }
/* finds entry in list, or returns NULL */ struct entry* find_match(struct entry* entries, ldns_pkt* query_pkt, enum transport_type transport) { struct entry* p = entries; ldns_pkt* reply = NULL; for(p=entries; p; p=p->next) { verbose(3, "comparepkt: "); reply = p->reply_list->reply; if(p->match_opcode && ldns_pkt_get_opcode(query_pkt) != ldns_pkt_get_opcode(reply)) { verbose(3, "bad opcode\n"); continue; } if(p->match_qtype && get_qtype(query_pkt) != get_qtype(reply)) { verbose(3, "bad qtype\n"); continue; } if(p->match_qname) { if(!get_owner(query_pkt) || !get_owner(reply) || ldns_dname_compare( get_owner(query_pkt), get_owner(reply)) != 0) { verbose(3, "bad qname\n"); continue; } } if(p->match_subdomain) { if(!get_owner(query_pkt) || !get_owner(reply) || (ldns_dname_compare(get_owner(query_pkt), get_owner(reply)) != 0 && !ldns_dname_is_subdomain( get_owner(query_pkt), get_owner(reply)))) { verbose(3, "bad subdomain\n"); continue; } } if(p->match_serial && get_serial(query_pkt) != p->ixfr_soa_serial) { verbose(3, "bad serial\n"); continue; } if(p->match_do && !ldns_pkt_edns_do(query_pkt)) { verbose(3, "no DO bit set\n"); continue; } if(p->match_noedns && ldns_pkt_edns(query_pkt)) { verbose(3, "bad; EDNS OPT present\n"); continue; } if(p->match_transport != transport_any && p->match_transport != transport) { verbose(3, "bad transport\n"); continue; } if(p->match_all && !match_all(query_pkt, reply, p->match_ttl)) { verbose(3, "bad allmatch\n"); continue; } verbose(3, "match!\n"); return p; } return NULL; }