diff options
Diffstat (limited to 'contrib/ldns/packet.c')
-rw-r--r-- | contrib/ldns/packet.c | 1113 |
1 files changed, 1113 insertions, 0 deletions
diff --git a/contrib/ldns/packet.c b/contrib/ldns/packet.c new file mode 100644 index 000000000000..d57e9e275ed2 --- /dev/null +++ b/contrib/ldns/packet.c @@ -0,0 +1,1113 @@ +/* + * packet.c + * + * dns packet implementation + * + * a Net::DNS like library for C + * + * (c) NLnet Labs, 2004-2006 + * + * See the file LICENSE for the license + */ + +#include <ldns/config.h> + +#include <ldns/ldns.h> + +#include <strings.h> +#include <limits.h> + +#ifdef HAVE_SSL +#include <openssl/rand.h> +#endif + +/* Access functions + * do this as functions to get type checking + */ + +#define LDNS_EDNS_MASK_DO_BIT 0x8000 + +/* TODO defines for 3600 */ +/* convert to and from numerical flag values */ +ldns_lookup_table ldns_edns_flags[] = { + { 3600, "do"}, + { 0, NULL} +}; + +/* read */ +uint16_t +ldns_pkt_id(const ldns_pkt *packet) +{ + return packet->_header->_id; +} + +bool +ldns_pkt_qr(const ldns_pkt *packet) +{ + return packet->_header->_qr; +} + +bool +ldns_pkt_aa(const ldns_pkt *packet) +{ + return packet->_header->_aa; +} + +bool +ldns_pkt_tc(const ldns_pkt *packet) +{ + return packet->_header->_tc; +} + +bool +ldns_pkt_rd(const ldns_pkt *packet) +{ + return packet->_header->_rd; +} + +bool +ldns_pkt_cd(const ldns_pkt *packet) +{ + return packet->_header->_cd; +} + +bool +ldns_pkt_ra(const ldns_pkt *packet) +{ + return packet->_header->_ra; +} + +bool +ldns_pkt_ad(const ldns_pkt *packet) +{ + return packet->_header->_ad; +} + +ldns_pkt_opcode +ldns_pkt_get_opcode(const ldns_pkt *packet) +{ + return packet->_header->_opcode; +} + +ldns_pkt_rcode +ldns_pkt_get_rcode(const ldns_pkt *packet) +{ + return packet->_header->_rcode; +} + +uint16_t +ldns_pkt_qdcount(const ldns_pkt *packet) +{ + return packet->_header->_qdcount; +} + +uint16_t +ldns_pkt_ancount(const ldns_pkt *packet) +{ + return packet->_header->_ancount; +} + +uint16_t +ldns_pkt_nscount(const ldns_pkt *packet) +{ + return packet->_header->_nscount; +} + +uint16_t +ldns_pkt_arcount(const ldns_pkt *packet) +{ + return packet->_header->_arcount; +} + +ldns_rr_list * +ldns_pkt_question(const ldns_pkt *packet) +{ + return packet->_question; +} + +ldns_rr_list * +ldns_pkt_answer(const ldns_pkt *packet) +{ + return packet->_answer; +} + +ldns_rr_list * +ldns_pkt_authority(const ldns_pkt *packet) +{ + return packet->_authority; +} + +ldns_rr_list * +ldns_pkt_additional(const ldns_pkt *packet) +{ + return packet->_additional; +} + +/* return ALL section concatenated */ +ldns_rr_list * +ldns_pkt_all(const ldns_pkt *packet) +{ + ldns_rr_list *all, *prev_all; + + all = ldns_rr_list_cat_clone( + ldns_pkt_question(packet), + ldns_pkt_answer(packet)); + prev_all = all; + all = ldns_rr_list_cat_clone(all, + ldns_pkt_authority(packet)); + ldns_rr_list_deep_free(prev_all); + prev_all = all; + all = ldns_rr_list_cat_clone(all, + ldns_pkt_additional(packet)); + ldns_rr_list_deep_free(prev_all); + return all; +} + +ldns_rr_list * +ldns_pkt_all_noquestion(const ldns_pkt *packet) +{ + ldns_rr_list *all, *all2; + + all = ldns_rr_list_cat_clone( + ldns_pkt_answer(packet), + ldns_pkt_authority(packet)); + all2 = ldns_rr_list_cat_clone(all, + ldns_pkt_additional(packet)); + + ldns_rr_list_deep_free(all); + return all2; +} + +size_t +ldns_pkt_size(const ldns_pkt *packet) +{ + return packet->_size; +} + +uint32_t +ldns_pkt_querytime(const ldns_pkt *packet) +{ + return packet->_querytime; +} + +ldns_rdf * +ldns_pkt_answerfrom(const ldns_pkt *packet) +{ + return packet->_answerfrom; +} + +struct timeval +ldns_pkt_timestamp(const ldns_pkt *packet) +{ + return packet->timestamp; +} + +uint16_t +ldns_pkt_edns_udp_size(const ldns_pkt *packet) +{ + return packet->_edns_udp_size; +} + +uint8_t +ldns_pkt_edns_extended_rcode(const ldns_pkt *packet) +{ + return packet->_edns_extended_rcode; +} + +uint8_t +ldns_pkt_edns_version(const ldns_pkt *packet) +{ + return packet->_edns_version; +} + +uint16_t +ldns_pkt_edns_z(const ldns_pkt *packet) +{ + return packet->_edns_z; +} + +bool +ldns_pkt_edns_do(const ldns_pkt *packet) +{ + return (packet->_edns_z & LDNS_EDNS_MASK_DO_BIT); +} + +void +ldns_pkt_set_edns_do(ldns_pkt *packet, bool value) +{ + if (value) { + packet->_edns_z = packet->_edns_z | LDNS_EDNS_MASK_DO_BIT; + } else { + packet->_edns_z = packet->_edns_z & ~LDNS_EDNS_MASK_DO_BIT; + } +} + +ldns_rdf * +ldns_pkt_edns_data(const ldns_pkt *packet) +{ + return packet->_edns_data; +} + +/* return only those rr that share the ownername */ +ldns_rr_list * +ldns_pkt_rr_list_by_name(ldns_pkt *packet, + ldns_rdf *ownername, + ldns_pkt_section sec) +{ + ldns_rr_list *rrs; + ldns_rr_list *ret; + uint16_t i; + + if (!packet) { + return NULL; + } + + rrs = ldns_pkt_get_section_clone(packet, sec); + ret = NULL; + + for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { + if (ldns_rdf_compare(ldns_rr_owner( + ldns_rr_list_rr(rrs, i)), + ownername) == 0) { + /* owner names match */ + if (ret == NULL) { + ret = ldns_rr_list_new(); + } + ldns_rr_list_push_rr(ret, ldns_rr_list_rr(rrs, i)); + } + } + return ret; +} + +/* return only those rr that share a type */ +ldns_rr_list * +ldns_pkt_rr_list_by_type(const ldns_pkt *packet, + ldns_rr_type type, + ldns_pkt_section sec) +{ + ldns_rr_list *rrs; + ldns_rr_list *new; + uint16_t i; + + if(!packet) { + return NULL; + } + + rrs = ldns_pkt_get_section_clone(packet, sec); + new = ldns_rr_list_new(); + + for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { + if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i))) { + /* types match */ + ldns_rr_list_push_rr(new, + ldns_rr_clone( + ldns_rr_list_rr(rrs, i)) + ); + } + } + ldns_rr_list_deep_free(rrs); + + if (ldns_rr_list_rr_count(new) == 0) { + ldns_rr_list_free(new); + return NULL; + } else { + return new; + } +} + +/* return only those rrs that share name and type */ +ldns_rr_list * +ldns_pkt_rr_list_by_name_and_type(const ldns_pkt *packet, + const ldns_rdf *ownername, + ldns_rr_type type, + ldns_pkt_section sec) +{ + ldns_rr_list *rrs; + ldns_rr_list *new; + ldns_rr_list *ret; + uint16_t i; + + if(!packet) { + return NULL; + } + + rrs = ldns_pkt_get_section_clone(packet, sec); + new = ldns_rr_list_new(); + ret = NULL; + + for(i = 0; i < ldns_rr_list_rr_count(rrs); i++) { + if (type == ldns_rr_get_type(ldns_rr_list_rr(rrs, i)) && + ldns_rdf_compare(ldns_rr_owner(ldns_rr_list_rr(rrs, i)), + ownername + ) == 0 + ) { + /* types match */ + ldns_rr_list_push_rr(new, ldns_rr_clone(ldns_rr_list_rr(rrs, i))); + ret = new; + } + } + ldns_rr_list_deep_free(rrs); + if (!ret) { + ldns_rr_list_free(new); + } + return ret; +} + +bool +ldns_pkt_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr) +{ + bool result = false; + + switch (sec) { + case LDNS_SECTION_QUESTION: + return ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr); + case LDNS_SECTION_ANSWER: + return ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr); + case LDNS_SECTION_AUTHORITY: + return ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr); + case LDNS_SECTION_ADDITIONAL: + return ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr); + case LDNS_SECTION_ANY: + result = ldns_rr_list_contains_rr(ldns_pkt_question(pkt), rr); + case LDNS_SECTION_ANY_NOQUESTION: + result = result + || ldns_rr_list_contains_rr(ldns_pkt_answer(pkt), rr) + || ldns_rr_list_contains_rr(ldns_pkt_authority(pkt), rr) + || ldns_rr_list_contains_rr(ldns_pkt_additional(pkt), rr); + } + + return result; +} + +static uint16_t +ldns_pkt_section_count(const ldns_pkt *packet, ldns_pkt_section s) +{ + switch(s) { + case LDNS_SECTION_QUESTION: + return ldns_pkt_qdcount(packet); + case LDNS_SECTION_ANSWER: + return ldns_pkt_ancount(packet); + case LDNS_SECTION_AUTHORITY: + return ldns_pkt_nscount(packet); + case LDNS_SECTION_ADDITIONAL: + return ldns_pkt_arcount(packet); + case LDNS_SECTION_ANY: + return ldns_pkt_qdcount(packet) + + ldns_pkt_ancount(packet) + + ldns_pkt_nscount(packet) + + ldns_pkt_arcount(packet); + case LDNS_SECTION_ANY_NOQUESTION: + return ldns_pkt_ancount(packet) + + ldns_pkt_nscount(packet) + + ldns_pkt_arcount(packet); + default: + return 0; + } +} + +bool +ldns_pkt_empty(ldns_pkt *p) +{ + if (!p) { + return true; /* NULL is empty? */ + } + if (ldns_pkt_section_count(p, LDNS_SECTION_ANY) > 0) { + return false; + } else { + return true; + } +} + + +ldns_rr_list * +ldns_pkt_get_section_clone(const ldns_pkt *packet, ldns_pkt_section s) +{ + switch(s) { + case LDNS_SECTION_QUESTION: + return ldns_rr_list_clone(ldns_pkt_question(packet)); + case LDNS_SECTION_ANSWER: + return ldns_rr_list_clone(ldns_pkt_answer(packet)); + case LDNS_SECTION_AUTHORITY: + return ldns_rr_list_clone(ldns_pkt_authority(packet)); + case LDNS_SECTION_ADDITIONAL: + return ldns_rr_list_clone(ldns_pkt_additional(packet)); + case LDNS_SECTION_ANY: + /* these are already clones */ + return ldns_pkt_all(packet); + case LDNS_SECTION_ANY_NOQUESTION: + return ldns_pkt_all_noquestion(packet); + default: + return NULL; + } +} + +ldns_rr *ldns_pkt_tsig(const ldns_pkt *pkt) { + return pkt->_tsig_rr; +} + +/* write */ +void +ldns_pkt_set_id(ldns_pkt *packet, uint16_t id) +{ + packet->_header->_id = id; +} + +void +ldns_pkt_set_random_id(ldns_pkt *packet) +{ + uint16_t rid = ldns_get_random(); + ldns_pkt_set_id(packet, rid); +} + + +void +ldns_pkt_set_qr(ldns_pkt *packet, bool qr) +{ + packet->_header->_qr = qr; +} + +void +ldns_pkt_set_aa(ldns_pkt *packet, bool aa) +{ + packet->_header->_aa = aa; +} + +void +ldns_pkt_set_tc(ldns_pkt *packet, bool tc) +{ + packet->_header->_tc = tc; +} + +void +ldns_pkt_set_rd(ldns_pkt *packet, bool rd) +{ + packet->_header->_rd = rd; +} + +void +ldns_pkt_set_additional(ldns_pkt *p, ldns_rr_list *rr) +{ + p->_additional = rr; +} + +void +ldns_pkt_set_question(ldns_pkt *p, ldns_rr_list *rr) +{ + p->_question = rr; +} + +void +ldns_pkt_set_answer(ldns_pkt *p, ldns_rr_list *rr) +{ + p->_answer = rr; +} + +void +ldns_pkt_set_authority(ldns_pkt *p, ldns_rr_list *rr) +{ + p->_authority = rr; +} + +void +ldns_pkt_set_cd(ldns_pkt *packet, bool cd) +{ + packet->_header->_cd = cd; +} + +void +ldns_pkt_set_ra(ldns_pkt *packet, bool ra) +{ + packet->_header->_ra = ra; +} + +void +ldns_pkt_set_ad(ldns_pkt *packet, bool ad) +{ + packet->_header->_ad = ad; +} + +void +ldns_pkt_set_opcode(ldns_pkt *packet, ldns_pkt_opcode opcode) +{ + packet->_header->_opcode = opcode; +} + +void +ldns_pkt_set_rcode(ldns_pkt *packet, uint8_t rcode) +{ + packet->_header->_rcode = rcode; +} + +void +ldns_pkt_set_qdcount(ldns_pkt *packet, uint16_t qdcount) +{ + packet->_header->_qdcount = qdcount; +} + +void +ldns_pkt_set_ancount(ldns_pkt *packet, uint16_t ancount) +{ + packet->_header->_ancount = ancount; +} + +void +ldns_pkt_set_nscount(ldns_pkt *packet, uint16_t nscount) +{ + packet->_header->_nscount = nscount; +} + +void +ldns_pkt_set_arcount(ldns_pkt *packet, uint16_t arcount) +{ + packet->_header->_arcount = arcount; +} + +void +ldns_pkt_set_querytime(ldns_pkt *packet, uint32_t time) +{ + packet->_querytime = time; +} + +void +ldns_pkt_set_answerfrom(ldns_pkt *packet, ldns_rdf *answerfrom) +{ + packet->_answerfrom = answerfrom; +} + +void +ldns_pkt_set_timestamp(ldns_pkt *packet, struct timeval timeval) +{ + packet->timestamp.tv_sec = timeval.tv_sec; + packet->timestamp.tv_usec = timeval.tv_usec; +} + +void +ldns_pkt_set_size(ldns_pkt *packet, size_t s) +{ + packet->_size = s; +} + +void +ldns_pkt_set_edns_udp_size(ldns_pkt *packet, uint16_t s) +{ + packet->_edns_udp_size = s; +} + +void +ldns_pkt_set_edns_extended_rcode(ldns_pkt *packet, uint8_t c) +{ + packet->_edns_extended_rcode = c; +} + +void +ldns_pkt_set_edns_version(ldns_pkt *packet, uint8_t v) +{ + packet->_edns_version = v; +} + +void +ldns_pkt_set_edns_z(ldns_pkt *packet, uint16_t z) +{ + packet->_edns_z = z; +} + +void +ldns_pkt_set_edns_data(ldns_pkt *packet, ldns_rdf *data) +{ + packet->_edns_data = data; +} + +void +ldns_pkt_set_section_count(ldns_pkt *packet, ldns_pkt_section s, uint16_t count) +{ + switch(s) { + case LDNS_SECTION_QUESTION: + ldns_pkt_set_qdcount(packet, count); + break; + case LDNS_SECTION_ANSWER: + ldns_pkt_set_ancount(packet, count); + break; + case LDNS_SECTION_AUTHORITY: + ldns_pkt_set_nscount(packet, count); + break; + case LDNS_SECTION_ADDITIONAL: + ldns_pkt_set_arcount(packet, count); + break; + case LDNS_SECTION_ANY: + case LDNS_SECTION_ANY_NOQUESTION: + break; + } +} + +void ldns_pkt_set_tsig(ldns_pkt *pkt, ldns_rr *rr) +{ + pkt->_tsig_rr = rr; +} + +bool +ldns_pkt_push_rr(ldns_pkt *packet, ldns_pkt_section section, ldns_rr *rr) +{ + switch(section) { + case LDNS_SECTION_QUESTION: + if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { + return false; + } + ldns_pkt_set_qdcount(packet, ldns_pkt_qdcount(packet) + 1); + break; + case LDNS_SECTION_ANSWER: + if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { + return false; + } + ldns_pkt_set_ancount(packet, ldns_pkt_ancount(packet) + 1); + break; + case LDNS_SECTION_AUTHORITY: + if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { + return false; + } + ldns_pkt_set_nscount(packet, ldns_pkt_nscount(packet) + 1); + break; + case LDNS_SECTION_ADDITIONAL: + if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { + return false; + } + ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) + 1); + break; + case LDNS_SECTION_ANY: + case LDNS_SECTION_ANY_NOQUESTION: + /* shouldn't this error? */ + break; + } + return true; +} + +bool +ldns_pkt_safe_push_rr(ldns_pkt *pkt, ldns_pkt_section sec, ldns_rr *rr) +{ + + /* check to see if its there */ + if (ldns_pkt_rr(pkt, sec, rr)) { + /* already there */ + return false; + } + return ldns_pkt_push_rr(pkt, sec, rr); +} + +bool +ldns_pkt_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list) +{ + size_t i; + for(i = 0; i < ldns_rr_list_rr_count(list); i++) { + if (!ldns_pkt_push_rr(p, s, ldns_rr_list_rr(list, i))) { + return false; + } + } + return true; +} + +bool +ldns_pkt_safe_push_rr_list(ldns_pkt *p, ldns_pkt_section s, ldns_rr_list *list) +{ + size_t i; + for(i = 0; i < ldns_rr_list_rr_count(list); i++) { + if (!ldns_pkt_safe_push_rr(p, s, ldns_rr_list_rr(list, i))) { + return false; + } + } + return true; +} + +bool +ldns_pkt_edns(const ldns_pkt *pkt) { + return (ldns_pkt_edns_udp_size(pkt) > 0 || + ldns_pkt_edns_extended_rcode(pkt) > 0 || + ldns_pkt_edns_data(pkt) || + ldns_pkt_edns_do(pkt) + ); +} + + +/* Create/destroy/convert functions + */ +ldns_pkt * +ldns_pkt_new(void) +{ + ldns_pkt *packet; + packet = LDNS_MALLOC(ldns_pkt); + if (!packet) { + return NULL; + } + + packet->_header = LDNS_MALLOC(ldns_hdr); + if (!packet->_header) { + LDNS_FREE(packet); + return NULL; + } + + packet->_question = ldns_rr_list_new(); + packet->_answer = ldns_rr_list_new(); + packet->_authority = ldns_rr_list_new(); + packet->_additional = ldns_rr_list_new(); + + /* default everything to false */ + ldns_pkt_set_qr(packet, false); + ldns_pkt_set_aa(packet, false); + ldns_pkt_set_tc(packet, false); + ldns_pkt_set_rd(packet, false); + ldns_pkt_set_ra(packet, false); + ldns_pkt_set_ad(packet, false); + ldns_pkt_set_cd(packet, false); + + ldns_pkt_set_opcode(packet, LDNS_PACKET_QUERY); + ldns_pkt_set_rcode(packet, 0); + ldns_pkt_set_id(packet, 0); + ldns_pkt_set_size(packet, 0); + ldns_pkt_set_querytime(packet, 0); + memset(&packet->timestamp, 0, sizeof(packet->timestamp)); + ldns_pkt_set_answerfrom(packet, NULL); + ldns_pkt_set_section_count(packet, LDNS_SECTION_QUESTION, 0); + ldns_pkt_set_section_count(packet, LDNS_SECTION_ANSWER, 0); + ldns_pkt_set_section_count(packet, LDNS_SECTION_AUTHORITY, 0); + ldns_pkt_set_section_count(packet, LDNS_SECTION_ADDITIONAL, 0); + + ldns_pkt_set_edns_udp_size(packet, 0); + ldns_pkt_set_edns_extended_rcode(packet, 0); + ldns_pkt_set_edns_version(packet, 0); + ldns_pkt_set_edns_z(packet, 0); + ldns_pkt_set_edns_data(packet, NULL); + + ldns_pkt_set_tsig(packet, NULL); + + return packet; +} + +void +ldns_pkt_free(ldns_pkt *packet) +{ + if (packet) { + LDNS_FREE(packet->_header); + ldns_rr_list_deep_free(packet->_question); + ldns_rr_list_deep_free(packet->_answer); + ldns_rr_list_deep_free(packet->_authority); + ldns_rr_list_deep_free(packet->_additional); + ldns_rr_free(packet->_tsig_rr); + ldns_rdf_deep_free(packet->_edns_data); + ldns_rdf_deep_free(packet->_answerfrom); + LDNS_FREE(packet); + } +} + +bool +ldns_pkt_set_flags(ldns_pkt *packet, uint16_t flags) +{ + if (!packet) { + return false; + } + if ((flags & LDNS_QR) == LDNS_QR) { + ldns_pkt_set_qr(packet, true); + } + if ((flags & LDNS_AA) == LDNS_AA) { + ldns_pkt_set_aa(packet, true); + } + if ((flags & LDNS_RD) == LDNS_RD) { + ldns_pkt_set_rd(packet, true); + } + if ((flags & LDNS_TC) == LDNS_TC) { + ldns_pkt_set_tc(packet, true); + } + if ((flags & LDNS_CD) == LDNS_CD) { + ldns_pkt_set_cd(packet, true); + } + if ((flags & LDNS_RA) == LDNS_RA) { + ldns_pkt_set_ra(packet, true); + } + if ((flags & LDNS_AD) == LDNS_AD) { + ldns_pkt_set_ad(packet, true); + } + return true; +} + + +static ldns_status +ldns_pkt_add_authsoa(ldns_pkt* packet, ldns_rdf* rr_name, ldns_rr_class rr_class) +{ + ldns_rr* soa_rr = ldns_rr_new(); + ldns_rdf *owner_rdf; + ldns_rdf *mname_rdf; + ldns_rdf *rname_rdf; + ldns_rdf *serial_rdf; + ldns_rdf *refresh_rdf; + ldns_rdf *retry_rdf; + ldns_rdf *expire_rdf; + ldns_rdf *minimum_rdf; + + if (!soa_rr) { + return LDNS_STATUS_MEM_ERR; + } + owner_rdf = ldns_rdf_clone(rr_name); + if (!owner_rdf) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } + + ldns_rr_set_owner(soa_rr, owner_rdf); + ldns_rr_set_type(soa_rr, LDNS_RR_TYPE_SOA); + ldns_rr_set_class(soa_rr, rr_class); + ldns_rr_set_question(soa_rr, false); + + if (ldns_str2rdf_dname(&mname_rdf, ".") != LDNS_STATUS_OK) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, mname_rdf); + } + if (ldns_str2rdf_dname(&rname_rdf, ".") != LDNS_STATUS_OK) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, rname_rdf); + } + serial_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); + if (!serial_rdf) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, serial_rdf); + } + refresh_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); + if (!refresh_rdf) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, refresh_rdf); + } + retry_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); + if (!retry_rdf) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, retry_rdf); + } + expire_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); + if (!expire_rdf) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, expire_rdf); + } + minimum_rdf = ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, 0); + if (!minimum_rdf) { + ldns_rr_free(soa_rr); + return LDNS_STATUS_MEM_ERR; + } else { + ldns_rr_push_rdf(soa_rr, minimum_rdf); + } + ldns_pkt_push_rr(packet, LDNS_SECTION_AUTHORITY, soa_rr); + return LDNS_STATUS_OK; +} + + +ldns_status +ldns_pkt_query_new_frm_str(ldns_pkt **p, const char *name, ldns_rr_type rr_type, + ldns_rr_class rr_class, uint16_t flags) +{ + ldns_pkt *packet; + ldns_rr *question_rr; + ldns_rdf *name_rdf; + + packet = ldns_pkt_new(); + if (!packet) { + return LDNS_STATUS_MEM_ERR; + } + + if (!ldns_pkt_set_flags(packet, flags)) { + return LDNS_STATUS_ERR; + } + + question_rr = ldns_rr_new(); + if (!question_rr) { + return LDNS_STATUS_MEM_ERR; + } + + if (rr_type == 0) { + rr_type = LDNS_RR_TYPE_A; + } + if (rr_class == 0) { + rr_class = LDNS_RR_CLASS_IN; + } + + if (ldns_str2rdf_dname(&name_rdf, name) == LDNS_STATUS_OK) { + ldns_rr_set_owner(question_rr, name_rdf); + ldns_rr_set_type(question_rr, rr_type); + ldns_rr_set_class(question_rr, rr_class); + ldns_rr_set_question(question_rr, true); + + ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); + } else { + ldns_rr_free(question_rr); + ldns_pkt_free(packet); + return LDNS_STATUS_ERR; + } + + /** IXFR? */ + if (rr_type == LDNS_RR_TYPE_IXFR) { + if (ldns_pkt_add_authsoa(packet, name_rdf, rr_class) != LDNS_STATUS_OK) { + ldns_pkt_free(packet); + return LDNS_STATUS_ERR; + } + } + + packet->_tsig_rr = NULL; + ldns_pkt_set_answerfrom(packet, NULL); + if (p) { + *p = packet; + return LDNS_STATUS_OK; + } else { + ldns_pkt_free(packet); + return LDNS_STATUS_NULL; + } +} + +ldns_pkt * +ldns_pkt_query_new(ldns_rdf *rr_name, ldns_rr_type rr_type, ldns_rr_class rr_class, + uint16_t flags) +{ + ldns_pkt *packet; + ldns_rr *question_rr; + + packet = ldns_pkt_new(); + if (!packet) { + return NULL; + } + + if (!ldns_pkt_set_flags(packet, flags)) { + return NULL; + } + + question_rr = ldns_rr_new(); + if (!question_rr) { + ldns_pkt_free(packet); + return NULL; + } + + if (rr_type == 0) { + rr_type = LDNS_RR_TYPE_A; + } + if (rr_class == 0) { + rr_class = LDNS_RR_CLASS_IN; + } + + ldns_rr_set_owner(question_rr, rr_name); + ldns_rr_set_type(question_rr, rr_type); + ldns_rr_set_class(question_rr, rr_class); + ldns_rr_set_question(question_rr, true); + ldns_pkt_push_rr(packet, LDNS_SECTION_QUESTION, question_rr); + + /** IXFR? */ + if (rr_type == LDNS_RR_TYPE_IXFR) { + if (ldns_pkt_add_authsoa(packet, rr_name, rr_class) != LDNS_STATUS_OK) { + ldns_pkt_free(packet); + return NULL; + } + } + + packet->_tsig_rr = NULL; + return packet; +} + +ldns_pkt_type +ldns_pkt_reply_type(ldns_pkt *p) +{ + ldns_rr_list *tmp; + + if (!p) { + return LDNS_PACKET_UNKNOWN; + } + + if (ldns_pkt_get_rcode(p) == LDNS_RCODE_NXDOMAIN) { + return LDNS_PACKET_NXDOMAIN; + } + + if (ldns_pkt_ancount(p) == 0 && ldns_pkt_arcount(p) == 0 + && ldns_pkt_nscount(p) == 1) { + + /* check for SOA */ + tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_SOA, + LDNS_SECTION_AUTHORITY); + if (tmp) { + ldns_rr_list_deep_free(tmp); + return LDNS_PACKET_NODATA; + } else { + /* I have no idea ... */ + } + } + + if (ldns_pkt_ancount(p) == 0 && ldns_pkt_nscount(p) > 0) { + tmp = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NS, + LDNS_SECTION_AUTHORITY); + if (tmp) { + /* there are nameservers here */ + ldns_rr_list_deep_free(tmp); + return LDNS_PACKET_REFERRAL; + } else { + /* I have no idea */ + } + ldns_rr_list_deep_free(tmp); + } + + /* if we cannot determine the packet type, we say it's an + * answer... + */ + return LDNS_PACKET_ANSWER; +} + +ldns_pkt * +ldns_pkt_clone(ldns_pkt *pkt) +{ + ldns_pkt *new_pkt; + + if (!pkt) { + return NULL; + } + new_pkt = ldns_pkt_new(); + + ldns_pkt_set_id(new_pkt, ldns_pkt_id(pkt)); + ldns_pkt_set_qr(new_pkt, ldns_pkt_qr(pkt)); + ldns_pkt_set_aa(new_pkt, ldns_pkt_aa(pkt)); + ldns_pkt_set_tc(new_pkt, ldns_pkt_tc(pkt)); + ldns_pkt_set_rd(new_pkt, ldns_pkt_rd(pkt)); + ldns_pkt_set_cd(new_pkt, ldns_pkt_cd(pkt)); + ldns_pkt_set_ra(new_pkt, ldns_pkt_ra(pkt)); + ldns_pkt_set_ad(new_pkt, ldns_pkt_ad(pkt)); + ldns_pkt_set_opcode(new_pkt, ldns_pkt_get_opcode(pkt)); + ldns_pkt_set_rcode(new_pkt, ldns_pkt_get_rcode(pkt)); + ldns_pkt_set_qdcount(new_pkt, ldns_pkt_qdcount(pkt)); + ldns_pkt_set_ancount(new_pkt, ldns_pkt_ancount(pkt)); + ldns_pkt_set_nscount(new_pkt, ldns_pkt_nscount(pkt)); + ldns_pkt_set_arcount(new_pkt, ldns_pkt_arcount(pkt)); + if (ldns_pkt_answerfrom(pkt)) + ldns_pkt_set_answerfrom(new_pkt, + ldns_rdf_clone(ldns_pkt_answerfrom(pkt))); + ldns_pkt_set_querytime(new_pkt, ldns_pkt_querytime(pkt)); + ldns_pkt_set_size(new_pkt, ldns_pkt_size(pkt)); + ldns_pkt_set_tsig(new_pkt, ldns_rr_clone(ldns_pkt_tsig(pkt))); + + ldns_pkt_set_edns_udp_size(new_pkt, ldns_pkt_edns_udp_size(pkt)); + ldns_pkt_set_edns_extended_rcode(new_pkt, + ldns_pkt_edns_extended_rcode(pkt)); + ldns_pkt_set_edns_version(new_pkt, ldns_pkt_edns_version(pkt)); + ldns_pkt_set_edns_z(new_pkt, ldns_pkt_edns_z(pkt)); + if(ldns_pkt_edns_data(pkt)) + ldns_pkt_set_edns_data(new_pkt, + ldns_rdf_clone(ldns_pkt_edns_data(pkt))); + ldns_pkt_set_edns_do(new_pkt, ldns_pkt_edns_do(pkt)); + + ldns_rr_list_deep_free(new_pkt->_question); + ldns_rr_list_deep_free(new_pkt->_answer); + ldns_rr_list_deep_free(new_pkt->_authority); + ldns_rr_list_deep_free(new_pkt->_additional); + new_pkt->_question = ldns_rr_list_clone(ldns_pkt_question(pkt)); + new_pkt->_answer = ldns_rr_list_clone(ldns_pkt_answer(pkt)); + new_pkt->_authority = ldns_rr_list_clone(ldns_pkt_authority(pkt)); + new_pkt->_additional = ldns_rr_list_clone(ldns_pkt_additional(pkt)); + return new_pkt; +} |