1238104Sdes/* 2238104Sdes * wire2host.c 3238104Sdes * 4238104Sdes * conversion routines from the wire to the host 5238104Sdes * format. 6238104Sdes * This will usually just a re-ordering of the 7238104Sdes * data (as we store it in network format) 8238104Sdes * 9238104Sdes * a Net::DNS like library for C 10238104Sdes * 11238104Sdes * (c) NLnet Labs, 2004-2006 12238104Sdes * 13238104Sdes * See the file LICENSE for the license 14238104Sdes */ 15238104Sdes 16238104Sdes 17238104Sdes#include <ldns/config.h> 18238104Sdes 19238104Sdes#include <ldns/ldns.h> 20238104Sdes/*#include <ldns/wire2host.h>*/ 21238104Sdes 22238104Sdes#include <strings.h> 23238104Sdes#include <limits.h> 24238104Sdes 25238104Sdes 26238104Sdes 27238104Sdes/* 28238104Sdes * Set of macro's to deal with the dns message header as specified 29238104Sdes * in RFC1035 in portable way. 30238104Sdes * 31238104Sdes */ 32238104Sdes 33238104Sdes/* 34238104Sdes * 35238104Sdes * 1 1 1 1 1 1 36238104Sdes * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 37238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 38238104Sdes * | ID | 39238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 40238104Sdes * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | 41238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 42238104Sdes * | QDCOUNT | 43238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 44238104Sdes * | ANCOUNT | 45238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 46238104Sdes * | NSCOUNT | 47238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 48238104Sdes * | ARCOUNT | 49238104Sdes * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 50238104Sdes * 51238104Sdes */ 52238104Sdes 53238104Sdes 54238104Sdes/* allocates memory to *dname! */ 55238104Sdesldns_status 56238104Sdesldns_wire2dname(ldns_rdf **dname, const uint8_t *wire, size_t max, size_t *pos) 57238104Sdes{ 58238104Sdes uint8_t label_size; 59238104Sdes uint16_t pointer_target; 60238104Sdes uint8_t pointer_target_buf[2]; 61238104Sdes size_t dname_pos = 0; 62238104Sdes size_t uncompressed_length = 0; 63238104Sdes size_t compression_pos = 0; 64238104Sdes uint8_t tmp_dname[LDNS_MAX_DOMAINLEN]; 65238104Sdes unsigned int pointer_count = 0; 66238104Sdes 67269257Sdes if (pos == NULL) { 68269257Sdes return LDNS_STATUS_WIRE_RDATA_ERR; 69269257Sdes } 70238104Sdes if (*pos >= max) { 71238104Sdes return LDNS_STATUS_PACKET_OVERFLOW; 72238104Sdes } 73238104Sdes label_size = wire[*pos]; 74238104Sdes while (label_size > 0) { 75238104Sdes /* compression */ 76238104Sdes while (label_size >= 192) { 77238104Sdes if (compression_pos == 0) { 78238104Sdes compression_pos = *pos + 2; 79238104Sdes } 80238104Sdes 81238104Sdes pointer_count++; 82238104Sdes 83238104Sdes /* remove first two bits */ 84238104Sdes if (*pos + 2 > max) { 85238104Sdes return LDNS_STATUS_PACKET_OVERFLOW; 86238104Sdes } 87238104Sdes pointer_target_buf[0] = wire[*pos] & 63; 88238104Sdes pointer_target_buf[1] = wire[*pos + 1]; 89238104Sdes pointer_target = ldns_read_uint16(pointer_target_buf); 90238104Sdes 91238104Sdes if (pointer_target == 0) { 92238104Sdes return LDNS_STATUS_INVALID_POINTER; 93238104Sdes } else if (pointer_target >= max) { 94238104Sdes return LDNS_STATUS_INVALID_POINTER; 95238104Sdes } else if (pointer_count > LDNS_MAX_POINTERS) { 96238104Sdes return LDNS_STATUS_INVALID_POINTER; 97238104Sdes } 98238104Sdes *pos = pointer_target; 99238104Sdes label_size = wire[*pos]; 100238104Sdes } 101238104Sdes if(label_size == 0) 102238104Sdes break; /* break from pointer to 0 byte */ 103238104Sdes if (label_size > LDNS_MAX_LABELLEN) { 104238104Sdes return LDNS_STATUS_LABEL_OVERFLOW; 105238104Sdes } 106238104Sdes if (*pos + 1 + label_size > max) { 107238104Sdes return LDNS_STATUS_LABEL_OVERFLOW; 108238104Sdes } 109238104Sdes 110238104Sdes /* check space for labelcount itself */ 111238104Sdes if (dname_pos + 1 > LDNS_MAX_DOMAINLEN) { 112238104Sdes return LDNS_STATUS_DOMAINNAME_OVERFLOW; 113238104Sdes } 114238104Sdes tmp_dname[dname_pos] = label_size; 115238104Sdes if (label_size > 0) { 116238104Sdes dname_pos++; 117238104Sdes } 118238104Sdes *pos = *pos + 1; 119238104Sdes if (dname_pos + label_size > LDNS_MAX_DOMAINLEN) { 120238104Sdes return LDNS_STATUS_DOMAINNAME_OVERFLOW; 121238104Sdes } 122238104Sdes memcpy(&tmp_dname[dname_pos], &wire[*pos], label_size); 123238104Sdes uncompressed_length += label_size + 1; 124238104Sdes dname_pos += label_size; 125238104Sdes *pos = *pos + label_size; 126238104Sdes 127238104Sdes if (*pos < max) { 128238104Sdes label_size = wire[*pos]; 129238104Sdes } 130238104Sdes } 131238104Sdes 132238104Sdes if (compression_pos > 0) { 133238104Sdes *pos = compression_pos; 134238104Sdes } else { 135238104Sdes *pos = *pos + 1; 136238104Sdes } 137238104Sdes 138238104Sdes if (dname_pos >= LDNS_MAX_DOMAINLEN) { 139238104Sdes return LDNS_STATUS_DOMAINNAME_OVERFLOW; 140238104Sdes } 141238104Sdes 142238104Sdes tmp_dname[dname_pos] = 0; 143238104Sdes dname_pos++; 144238104Sdes 145238104Sdes *dname = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, 146238104Sdes (uint16_t) dname_pos, tmp_dname); 147238104Sdes if (!*dname) { 148238104Sdes return LDNS_STATUS_MEM_ERR; 149238104Sdes } 150238104Sdes return LDNS_STATUS_OK; 151238104Sdes} 152238104Sdes 153238104Sdes/* maybe make this a goto error so data can be freed or something/ */ 154238104Sdes#define LDNS_STATUS_CHECK_RETURN(st) {if (st != LDNS_STATUS_OK) { return st; }} 155238104Sdes#define LDNS_STATUS_CHECK_GOTO(st, label) {if (st != LDNS_STATUS_OK) { /*printf("STG %s:%d: status code %d\n", __FILE__, __LINE__, st);*/ goto label; }} 156238104Sdes 157238104Sdesldns_status 158238104Sdesldns_wire2rdf(ldns_rr *rr, const uint8_t *wire, size_t max, size_t *pos) 159238104Sdes{ 160238104Sdes size_t end; 161238104Sdes size_t cur_rdf_length; 162238104Sdes uint8_t rdf_index; 163238104Sdes uint8_t *data; 164238104Sdes uint16_t rd_length; 165238104Sdes ldns_rdf *cur_rdf = NULL; 166238104Sdes ldns_rdf_type cur_rdf_type; 167269257Sdes const ldns_rr_descriptor *descriptor; 168238104Sdes ldns_status status; 169238104Sdes 170269257Sdes assert(rr != NULL); 171269257Sdes 172269257Sdes descriptor = ldns_rr_descript(ldns_rr_get_type(rr)); 173269257Sdes 174238104Sdes if (*pos + 2 > max) { 175238104Sdes return LDNS_STATUS_PACKET_OVERFLOW; 176238104Sdes } 177238104Sdes 178238104Sdes rd_length = ldns_read_uint16(&wire[*pos]); 179238104Sdes *pos = *pos + 2; 180238104Sdes 181238104Sdes if (*pos + rd_length > max) { 182238104Sdes return LDNS_STATUS_PACKET_OVERFLOW; 183238104Sdes } 184238104Sdes 185238104Sdes end = *pos + (size_t) rd_length; 186238104Sdes 187269257Sdes rdf_index = 0; 188269257Sdes while (*pos < end && 189269257Sdes rdf_index < ldns_rr_descriptor_maximum(descriptor)) { 190269257Sdes 191238104Sdes cur_rdf_length = 0; 192238104Sdes 193269257Sdes cur_rdf_type = ldns_rr_descriptor_field_type( 194269257Sdes descriptor, rdf_index); 195269257Sdes 196238104Sdes /* handle special cases immediately, set length 197238104Sdes for fixed length rdata and do them below */ 198238104Sdes switch (cur_rdf_type) { 199238104Sdes case LDNS_RDF_TYPE_DNAME: 200238104Sdes status = ldns_wire2dname(&cur_rdf, wire, max, pos); 201238104Sdes LDNS_STATUS_CHECK_RETURN(status); 202238104Sdes break; 203238104Sdes case LDNS_RDF_TYPE_CLASS: 204238104Sdes case LDNS_RDF_TYPE_ALG: 205238104Sdes case LDNS_RDF_TYPE_INT8: 206238104Sdes cur_rdf_length = LDNS_RDF_SIZE_BYTE; 207238104Sdes break; 208238104Sdes case LDNS_RDF_TYPE_TYPE: 209238104Sdes case LDNS_RDF_TYPE_INT16: 210238104Sdes case LDNS_RDF_TYPE_CERT_ALG: 211238104Sdes cur_rdf_length = LDNS_RDF_SIZE_WORD; 212238104Sdes break; 213238104Sdes case LDNS_RDF_TYPE_TIME: 214238104Sdes case LDNS_RDF_TYPE_INT32: 215238104Sdes case LDNS_RDF_TYPE_A: 216238104Sdes case LDNS_RDF_TYPE_PERIOD: 217238104Sdes cur_rdf_length = LDNS_RDF_SIZE_DOUBLEWORD; 218238104Sdes break; 219238104Sdes case LDNS_RDF_TYPE_TSIGTIME: 220269257Sdes case LDNS_RDF_TYPE_EUI48: 221238104Sdes cur_rdf_length = LDNS_RDF_SIZE_6BYTES; 222238104Sdes break; 223269257Sdes case LDNS_RDF_TYPE_ILNP64: 224269257Sdes case LDNS_RDF_TYPE_EUI64: 225269257Sdes cur_rdf_length = LDNS_RDF_SIZE_8BYTES; 226269257Sdes break; 227238104Sdes case LDNS_RDF_TYPE_AAAA: 228238104Sdes cur_rdf_length = LDNS_RDF_SIZE_16BYTES; 229238104Sdes break; 230238104Sdes case LDNS_RDF_TYPE_STR: 231238104Sdes case LDNS_RDF_TYPE_NSEC3_SALT: 232269257Sdes case LDNS_RDF_TYPE_TAG: 233238104Sdes /* len is stored in first byte 234238104Sdes * it should be in the rdf too, so just 235238104Sdes * copy len+1 from this position 236238104Sdes */ 237238104Sdes cur_rdf_length = ((size_t) wire[*pos]) + 1; 238238104Sdes break; 239269257Sdes 240238104Sdes case LDNS_RDF_TYPE_INT16_DATA: 241269257Sdes if (*pos + 2 > end) { 242269257Sdes return LDNS_STATUS_PACKET_OVERFLOW; 243269257Sdes } 244269257Sdes cur_rdf_length = 245269257Sdes (size_t) ldns_read_uint16(&wire[*pos]) + 2; 246238104Sdes break; 247269257Sdes case LDNS_RDF_TYPE_HIP: 248269257Sdes if (*pos + 4 > end) { 249269257Sdes return LDNS_STATUS_PACKET_OVERFLOW; 250269257Sdes } 251269257Sdes cur_rdf_length = 252269257Sdes (size_t) wire[*pos] + 253269257Sdes (size_t) ldns_read_uint16(&wire[*pos + 2]) + 4; 254269257Sdes break; 255238104Sdes case LDNS_RDF_TYPE_B32_EXT: 256238104Sdes case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 257238104Sdes /* length is stored in first byte */ 258238104Sdes cur_rdf_length = ((size_t) wire[*pos]) + 1; 259238104Sdes break; 260238104Sdes case LDNS_RDF_TYPE_APL: 261238104Sdes case LDNS_RDF_TYPE_B64: 262238104Sdes case LDNS_RDF_TYPE_HEX: 263238104Sdes case LDNS_RDF_TYPE_NSEC: 264238104Sdes case LDNS_RDF_TYPE_UNKNOWN: 265238104Sdes case LDNS_RDF_TYPE_SERVICE: 266238104Sdes case LDNS_RDF_TYPE_LOC: 267238104Sdes case LDNS_RDF_TYPE_WKS: 268238104Sdes case LDNS_RDF_TYPE_NSAP: 269238104Sdes case LDNS_RDF_TYPE_ATMA: 270238104Sdes case LDNS_RDF_TYPE_IPSECKEY: 271269257Sdes case LDNS_RDF_TYPE_LONG_STR: 272238104Sdes case LDNS_RDF_TYPE_NONE: 273238104Sdes /* 274238104Sdes * Read to end of rr rdata 275238104Sdes */ 276238104Sdes cur_rdf_length = end - *pos; 277238104Sdes break; 278238104Sdes } 279238104Sdes 280238104Sdes /* fixed length rdata */ 281238104Sdes if (cur_rdf_length > 0) { 282238104Sdes if (cur_rdf_length + *pos > end) { 283238104Sdes return LDNS_STATUS_PACKET_OVERFLOW; 284238104Sdes } 285238104Sdes data = LDNS_XMALLOC(uint8_t, rd_length); 286238104Sdes if (!data) { 287238104Sdes return LDNS_STATUS_MEM_ERR; 288238104Sdes } 289238104Sdes memcpy(data, &wire[*pos], cur_rdf_length); 290238104Sdes 291269257Sdes cur_rdf = ldns_rdf_new(cur_rdf_type, 292269257Sdes cur_rdf_length, data); 293238104Sdes *pos = *pos + cur_rdf_length; 294238104Sdes } 295238104Sdes 296238104Sdes if (cur_rdf) { 297238104Sdes ldns_rr_push_rdf(rr, cur_rdf); 298238104Sdes cur_rdf = NULL; 299238104Sdes } 300238104Sdes 301269257Sdes rdf_index++; 302269257Sdes 303269257Sdes } /* while (rdf_index < ldns_rr_descriptor_maximum(descriptor)) */ 304269257Sdes 305269257Sdes 306238104Sdes return LDNS_STATUS_OK; 307238104Sdes} 308238104Sdes 309238104Sdes 310238104Sdes/* TODO: 311238104Sdes can *pos be incremented at READ_INT? or maybe use something like 312238104Sdes RR_CLASS(wire)? 313238104Sdes uhhm Jelte?? 314238104Sdes*/ 315238104Sdesldns_status 316238104Sdesldns_wire2rr(ldns_rr **rr_p, const uint8_t *wire, size_t max, 317238104Sdes size_t *pos, ldns_pkt_section section) 318238104Sdes{ 319238104Sdes ldns_rdf *owner = NULL; 320238104Sdes ldns_rr *rr = ldns_rr_new(); 321238104Sdes ldns_status status; 322238104Sdes 323238104Sdes status = ldns_wire2dname(&owner, wire, max, pos); 324238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 325238104Sdes 326238104Sdes ldns_rr_set_owner(rr, owner); 327238104Sdes 328238104Sdes if (*pos + 4 > max) { 329238104Sdes status = LDNS_STATUS_PACKET_OVERFLOW; 330238104Sdes goto status_error; 331238104Sdes } 332238104Sdes 333238104Sdes ldns_rr_set_type(rr, ldns_read_uint16(&wire[*pos])); 334238104Sdes *pos = *pos + 2; 335238104Sdes 336238104Sdes ldns_rr_set_class(rr, ldns_read_uint16(&wire[*pos])); 337238104Sdes *pos = *pos + 2; 338238104Sdes 339238104Sdes if (section != LDNS_SECTION_QUESTION) { 340238104Sdes if (*pos + 4 > max) { 341238104Sdes status = LDNS_STATUS_PACKET_OVERFLOW; 342238104Sdes goto status_error; 343238104Sdes } 344238104Sdes ldns_rr_set_ttl(rr, ldns_read_uint32(&wire[*pos])); 345238104Sdes 346238104Sdes *pos = *pos + 4; 347238104Sdes status = ldns_wire2rdf(rr, wire, max, pos); 348238104Sdes 349238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 350238104Sdes ldns_rr_set_question(rr, false); 351238104Sdes } else { 352238104Sdes ldns_rr_set_question(rr, true); 353238104Sdes } 354238104Sdes 355238104Sdes *rr_p = rr; 356238104Sdes return LDNS_STATUS_OK; 357238104Sdes 358238104Sdesstatus_error: 359238104Sdes ldns_rr_free(rr); 360238104Sdes return status; 361238104Sdes} 362238104Sdes 363238104Sdesstatic ldns_status 364238104Sdesldns_wire2pkt_hdr(ldns_pkt *packet, const uint8_t *wire, size_t max, size_t *pos) 365238104Sdes{ 366238104Sdes if (*pos + LDNS_HEADER_SIZE > max) { 367238104Sdes return LDNS_STATUS_WIRE_INCOMPLETE_HEADER; 368238104Sdes } else { 369238104Sdes ldns_pkt_set_id(packet, LDNS_ID_WIRE(wire)); 370238104Sdes ldns_pkt_set_qr(packet, LDNS_QR_WIRE(wire)); 371238104Sdes ldns_pkt_set_opcode(packet, LDNS_OPCODE_WIRE(wire)); 372238104Sdes ldns_pkt_set_aa(packet, LDNS_AA_WIRE(wire)); 373238104Sdes ldns_pkt_set_tc(packet, LDNS_TC_WIRE(wire)); 374238104Sdes ldns_pkt_set_rd(packet, LDNS_RD_WIRE(wire)); 375238104Sdes ldns_pkt_set_ra(packet, LDNS_RA_WIRE(wire)); 376238104Sdes ldns_pkt_set_ad(packet, LDNS_AD_WIRE(wire)); 377238104Sdes ldns_pkt_set_cd(packet, LDNS_CD_WIRE(wire)); 378238104Sdes ldns_pkt_set_rcode(packet, LDNS_RCODE_WIRE(wire)); 379238104Sdes 380238104Sdes ldns_pkt_set_qdcount(packet, LDNS_QDCOUNT(wire)); 381238104Sdes ldns_pkt_set_ancount(packet, LDNS_ANCOUNT(wire)); 382238104Sdes ldns_pkt_set_nscount(packet, LDNS_NSCOUNT(wire)); 383238104Sdes ldns_pkt_set_arcount(packet, LDNS_ARCOUNT(wire)); 384238104Sdes 385238104Sdes *pos += LDNS_HEADER_SIZE; 386238104Sdes 387238104Sdes return LDNS_STATUS_OK; 388238104Sdes } 389238104Sdes} 390238104Sdes 391238104Sdesldns_status 392238104Sdesldns_buffer2pkt_wire(ldns_pkt **packet, ldns_buffer *buffer) 393238104Sdes{ 394238104Sdes /* lazy */ 395238104Sdes return ldns_wire2pkt(packet, ldns_buffer_begin(buffer), 396238104Sdes ldns_buffer_limit(buffer)); 397238104Sdes 398238104Sdes} 399238104Sdes 400238104Sdesldns_status 401238104Sdesldns_wire2pkt(ldns_pkt **packet_p, const uint8_t *wire, size_t max) 402238104Sdes{ 403238104Sdes size_t pos = 0; 404238104Sdes uint16_t i; 405238104Sdes ldns_rr *rr; 406238104Sdes ldns_pkt *packet = ldns_pkt_new(); 407238104Sdes ldns_status status = LDNS_STATUS_OK; 408238104Sdes int have_edns = 0; 409238104Sdes 410238104Sdes uint8_t data[4]; 411238104Sdes 412238104Sdes status = ldns_wire2pkt_hdr(packet, wire, max, &pos); 413238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 414238104Sdes 415238104Sdes for (i = 0; i < ldns_pkt_qdcount(packet); i++) { 416238104Sdes 417238104Sdes status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_QUESTION); 418238104Sdes if (status == LDNS_STATUS_PACKET_OVERFLOW) { 419238104Sdes status = LDNS_STATUS_WIRE_INCOMPLETE_QUESTION; 420238104Sdes } 421238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 422238104Sdes if (!ldns_rr_list_push_rr(ldns_pkt_question(packet), rr)) { 423238104Sdes ldns_pkt_free(packet); 424238104Sdes return LDNS_STATUS_INTERNAL_ERR; 425238104Sdes } 426238104Sdes } 427238104Sdes for (i = 0; i < ldns_pkt_ancount(packet); i++) { 428238104Sdes status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ANSWER); 429238104Sdes if (status == LDNS_STATUS_PACKET_OVERFLOW) { 430238104Sdes status = LDNS_STATUS_WIRE_INCOMPLETE_ANSWER; 431238104Sdes } 432238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 433238104Sdes if (!ldns_rr_list_push_rr(ldns_pkt_answer(packet), rr)) { 434238104Sdes ldns_pkt_free(packet); 435238104Sdes return LDNS_STATUS_INTERNAL_ERR; 436238104Sdes } 437238104Sdes } 438238104Sdes for (i = 0; i < ldns_pkt_nscount(packet); i++) { 439238104Sdes status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_AUTHORITY); 440238104Sdes if (status == LDNS_STATUS_PACKET_OVERFLOW) { 441238104Sdes status = LDNS_STATUS_WIRE_INCOMPLETE_AUTHORITY; 442238104Sdes } 443238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 444238104Sdes if (!ldns_rr_list_push_rr(ldns_pkt_authority(packet), rr)) { 445238104Sdes ldns_pkt_free(packet); 446238104Sdes return LDNS_STATUS_INTERNAL_ERR; 447238104Sdes } 448238104Sdes } 449238104Sdes for (i = 0; i < ldns_pkt_arcount(packet); i++) { 450238104Sdes status = ldns_wire2rr(&rr, wire, max, &pos, LDNS_SECTION_ADDITIONAL); 451238104Sdes if (status == LDNS_STATUS_PACKET_OVERFLOW) { 452238104Sdes status = LDNS_STATUS_WIRE_INCOMPLETE_ADDITIONAL; 453238104Sdes } 454238104Sdes LDNS_STATUS_CHECK_GOTO(status, status_error); 455238104Sdes 456238104Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_OPT) { 457238104Sdes ldns_pkt_set_edns_udp_size(packet, ldns_rr_get_class(rr)); 458238104Sdes ldns_write_uint32(data, ldns_rr_ttl(rr)); 459238104Sdes ldns_pkt_set_edns_extended_rcode(packet, data[0]); 460238104Sdes ldns_pkt_set_edns_version(packet, data[1]); 461238104Sdes ldns_pkt_set_edns_z(packet, ldns_read_uint16(&data[2])); 462238104Sdes /* edns might not have rdfs */ 463238104Sdes if (ldns_rr_rdf(rr, 0)) { 464238104Sdes ldns_pkt_set_edns_data(packet, ldns_rdf_clone(ldns_rr_rdf(rr, 0))); 465238104Sdes } 466238104Sdes ldns_rr_free(rr); 467238104Sdes have_edns += 1; 468238104Sdes } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_TSIG) { 469238104Sdes ldns_pkt_set_tsig(packet, rr); 470238104Sdes ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) - 1); 471238104Sdes } else if (!ldns_rr_list_push_rr(ldns_pkt_additional(packet), rr)) { 472238104Sdes ldns_pkt_free(packet); 473238104Sdes return LDNS_STATUS_INTERNAL_ERR; 474238104Sdes } 475238104Sdes } 476238104Sdes ldns_pkt_set_size(packet, max); 477238104Sdes if(have_edns) 478238104Sdes ldns_pkt_set_arcount(packet, ldns_pkt_arcount(packet) 479238104Sdes - have_edns); 480238104Sdes 481238104Sdes *packet_p = packet; 482238104Sdes return status; 483238104Sdes 484238104Sdesstatus_error: 485238104Sdes ldns_pkt_free(packet); 486238104Sdes return status; 487238104Sdes} 488