1238104Sdes/* 2238104Sdes * host2wire.c 3238104Sdes * 4238104Sdes * conversion routines from the host to the wire format. 5238104Sdes * This will usually just a re-ordering of the 6238104Sdes * data (as we store it in network format) 7238104Sdes * 8238104Sdes * a Net::DNS like library for C 9238104Sdes * 10238104Sdes * (c) NLnet Labs, 2004-2006 11238104Sdes * 12238104Sdes * See the file LICENSE for the license 13238104Sdes */ 14238104Sdes 15238104Sdes#include <ldns/config.h> 16238104Sdes 17238104Sdes#include <ldns/ldns.h> 18238104Sdes 19238104Sdes/* TODO Jelte 20238104Sdes add a pointer to a 'possiblecompression' structure 21238104Sdes to all the needed functions? 22238104Sdes something like an array of name, pointer values? 23238104Sdes every dname part could be added to it 24238104Sdes*/ 25238104Sdes 26238104Sdesldns_status 27238104Sdesldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name) 28238104Sdes{ 29238104Sdes if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) { 30238104Sdes ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name)); 31238104Sdes } 32238104Sdes return ldns_buffer_status(buffer); 33238104Sdes} 34238104Sdes 35238104Sdesldns_status 36238104Sdesldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf) 37238104Sdes{ 38238104Sdes if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { 39238104Sdes ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf)); 40238104Sdes } 41238104Sdes return ldns_buffer_status(buffer); 42238104Sdes} 43238104Sdes 44238104Sdesldns_status 45238104Sdesldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf) 46238104Sdes{ 47238104Sdes size_t i; 48238104Sdes uint8_t *rdf_data; 49238104Sdes 50238104Sdes if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) { 51238104Sdes if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { 52238104Sdes rdf_data = ldns_rdf_data(rdf); 53238104Sdes for (i = 0; i < ldns_rdf_size(rdf); i++) { 54238104Sdes ldns_buffer_write_u8(buffer, 55238104Sdes (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i])); 56238104Sdes } 57238104Sdes } 58238104Sdes } else { 59238104Sdes /* direct copy for all other types */ 60238104Sdes if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { 61238104Sdes ldns_buffer_write(buffer, 62238104Sdes ldns_rdf_data(rdf), 63238104Sdes ldns_rdf_size(rdf)); 64238104Sdes } 65238104Sdes } 66238104Sdes return ldns_buffer_status(buffer); 67238104Sdes} 68238104Sdes 69238104Sdes/* convert a rr list to wireformat */ 70238104Sdesldns_status 71238104Sdesldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list) 72238104Sdes{ 73238104Sdes uint16_t rr_count; 74238104Sdes uint16_t i; 75238104Sdes 76238104Sdes rr_count = ldns_rr_list_rr_count(rr_list); 77238104Sdes for(i = 0; i < rr_count; i++) { 78238104Sdes (void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), 79238104Sdes LDNS_SECTION_ANY); 80238104Sdes } 81238104Sdes return ldns_buffer_status(buffer); 82238104Sdes} 83238104Sdes 84238104Sdesldns_status 85238104Sdesldns_rr2buffer_wire_canonical(ldns_buffer *buffer, 86238104Sdes const ldns_rr *rr, 87238104Sdes int section) 88238104Sdes{ 89238104Sdes uint16_t i; 90238104Sdes uint16_t rdl_pos = 0; 91238104Sdes bool pre_rfc3597 = false; 92238104Sdes switch (ldns_rr_get_type(rr)) { 93238104Sdes case LDNS_RR_TYPE_NS: 94238104Sdes case LDNS_RR_TYPE_MD: 95238104Sdes case LDNS_RR_TYPE_MF: 96238104Sdes case LDNS_RR_TYPE_CNAME: 97238104Sdes case LDNS_RR_TYPE_SOA: 98238104Sdes case LDNS_RR_TYPE_MB: 99238104Sdes case LDNS_RR_TYPE_MG: 100238104Sdes case LDNS_RR_TYPE_MR: 101238104Sdes case LDNS_RR_TYPE_PTR: 102238104Sdes case LDNS_RR_TYPE_HINFO: 103238104Sdes case LDNS_RR_TYPE_MINFO: 104238104Sdes case LDNS_RR_TYPE_MX: 105238104Sdes case LDNS_RR_TYPE_RP: 106238104Sdes case LDNS_RR_TYPE_AFSDB: 107238104Sdes case LDNS_RR_TYPE_RT: 108238104Sdes case LDNS_RR_TYPE_SIG: 109238104Sdes case LDNS_RR_TYPE_PX: 110238104Sdes case LDNS_RR_TYPE_NXT: 111238104Sdes case LDNS_RR_TYPE_NAPTR: 112238104Sdes case LDNS_RR_TYPE_KX: 113238104Sdes case LDNS_RR_TYPE_SRV: 114238104Sdes case LDNS_RR_TYPE_DNAME: 115238104Sdes case LDNS_RR_TYPE_A6: 116238104Sdes case LDNS_RR_TYPE_RRSIG: 117238104Sdes pre_rfc3597 = true; 118238104Sdes break; 119238104Sdes default: 120238104Sdes break; 121238104Sdes } 122238104Sdes 123238104Sdes if (ldns_rr_owner(rr)) { 124238104Sdes (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr)); 125238104Sdes } 126238104Sdes 127238104Sdes if (ldns_buffer_reserve(buffer, 4)) { 128238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); 129238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); 130238104Sdes } 131238104Sdes 132238104Sdes if (section != LDNS_SECTION_QUESTION) { 133238104Sdes if (ldns_buffer_reserve(buffer, 6)) { 134238104Sdes ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); 135238104Sdes /* remember pos for later */ 136238104Sdes rdl_pos = ldns_buffer_position(buffer); 137238104Sdes ldns_buffer_write_u16(buffer, 0); 138238104Sdes } 139238104Sdes 140238104Sdes for (i = 0; i < ldns_rr_rd_count(rr); i++) { 141238104Sdes if (pre_rfc3597) { 142238104Sdes (void) ldns_rdf2buffer_wire_canonical( 143238104Sdes buffer, ldns_rr_rdf(rr, i)); 144238104Sdes } else { 145238104Sdes (void) ldns_rdf2buffer_wire( 146238104Sdes buffer, ldns_rr_rdf(rr, i)); 147238104Sdes } 148238104Sdes } 149238104Sdes 150238104Sdes if (rdl_pos != 0) { 151238104Sdes ldns_buffer_write_u16_at(buffer, rdl_pos, 152238104Sdes ldns_buffer_position(buffer) 153238104Sdes - rdl_pos - 2); 154238104Sdes } 155238104Sdes } 156238104Sdes return ldns_buffer_status(buffer); 157238104Sdes} 158238104Sdes 159238104Sdesldns_status 160238104Sdesldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section) 161238104Sdes{ 162238104Sdes uint16_t i; 163238104Sdes uint16_t rdl_pos = 0; 164238104Sdes 165238104Sdes if (ldns_rr_owner(rr)) { 166238104Sdes (void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr)); 167238104Sdes } 168238104Sdes 169238104Sdes if (ldns_buffer_reserve(buffer, 4)) { 170238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); 171238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); 172238104Sdes } 173238104Sdes 174238104Sdes if (section != LDNS_SECTION_QUESTION) { 175238104Sdes if (ldns_buffer_reserve(buffer, 6)) { 176238104Sdes ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); 177238104Sdes /* remember pos for later */ 178238104Sdes rdl_pos = ldns_buffer_position(buffer); 179238104Sdes ldns_buffer_write_u16(buffer, 0); 180238104Sdes } 181238104Sdes 182238104Sdes for (i = 0; i < ldns_rr_rd_count(rr); i++) { 183238104Sdes (void) ldns_rdf2buffer_wire( 184238104Sdes buffer, ldns_rr_rdf(rr, i)); 185238104Sdes } 186238104Sdes 187238104Sdes if (rdl_pos != 0) { 188238104Sdes ldns_buffer_write_u16_at(buffer, rdl_pos, 189238104Sdes ldns_buffer_position(buffer) 190238104Sdes - rdl_pos - 2); 191238104Sdes } 192238104Sdes } 193238104Sdes return ldns_buffer_status(buffer); 194238104Sdes} 195238104Sdes 196238104Sdesldns_status 197238104Sdesldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) 198238104Sdes{ 199238104Sdes uint16_t i; 200238104Sdes 201238104Sdes /* it must be a sig RR */ 202238104Sdes if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { 203238104Sdes return LDNS_STATUS_ERR; 204238104Sdes } 205238104Sdes 206238104Sdes /* Convert all the rdfs, except the actual signature data 207238104Sdes * rdf number 8 - the last, hence: -1 */ 208238104Sdes for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) { 209238104Sdes (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_rdf(rr, i)); 210238104Sdes } 211238104Sdes 212238104Sdes return ldns_buffer_status(buffer); 213238104Sdes} 214238104Sdes 215238104Sdesldns_status 216238104Sdesldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) 217238104Sdes{ 218238104Sdes uint16_t i; 219238104Sdes /* convert all the rdf's */ 220238104Sdes for (i = 0; i < ldns_rr_rd_count(rr); i++) { 221238104Sdes (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr, i)); 222238104Sdes } 223238104Sdes 224238104Sdes return ldns_buffer_status(buffer); 225238104Sdes} 226238104Sdes 227238104Sdes/* 228238104Sdes * Copies the packet header data to the buffer in wire format 229238104Sdes */ 230238104Sdesstatic ldns_status 231238104Sdesldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) 232238104Sdes{ 233238104Sdes uint8_t flags; 234238104Sdes uint16_t arcount; 235238104Sdes 236238104Sdes if (ldns_buffer_reserve(buffer, 12)) { 237238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_id(packet)); 238238104Sdes 239238104Sdes flags = ldns_pkt_qr(packet) << 7 240238104Sdes | ldns_pkt_get_opcode(packet) << 3 241238104Sdes | ldns_pkt_aa(packet) << 2 242238104Sdes | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet); 243238104Sdes ldns_buffer_write_u8(buffer, flags); 244238104Sdes 245238104Sdes flags = ldns_pkt_ra(packet) << 7 246238104Sdes /*| ldns_pkt_z(packet) << 6*/ 247238104Sdes | ldns_pkt_ad(packet) << 5 248238104Sdes | ldns_pkt_cd(packet) << 4 | ldns_pkt_get_rcode(packet); 249238104Sdes ldns_buffer_write_u8(buffer, flags); 250238104Sdes 251238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet)); 252238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet)); 253238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet)); 254238104Sdes /* add EDNS0 and TSIG to additional if they are there */ 255238104Sdes arcount = ldns_pkt_arcount(packet); 256238104Sdes if (ldns_pkt_tsig(packet)) { 257238104Sdes arcount++; 258238104Sdes } 259238104Sdes if (ldns_pkt_edns(packet)) { 260238104Sdes arcount++; 261238104Sdes } 262238104Sdes ldns_buffer_write_u16(buffer, arcount); 263238104Sdes } 264238104Sdes 265238104Sdes return ldns_buffer_status(buffer); 266238104Sdes} 267238104Sdes 268238104Sdesldns_status 269238104Sdesldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) 270238104Sdes{ 271238104Sdes ldns_rr_list *rr_list; 272238104Sdes uint16_t i; 273238104Sdes 274238104Sdes /* edns tmp vars */ 275238104Sdes ldns_rr *edns_rr; 276238104Sdes uint8_t edata[4]; 277238104Sdes 278238104Sdes (void) ldns_hdr2buffer_wire(buffer, packet); 279238104Sdes 280238104Sdes rr_list = ldns_pkt_question(packet); 281238104Sdes if (rr_list) { 282238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 283238104Sdes (void) ldns_rr2buffer_wire(buffer, 284238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION); 285238104Sdes } 286238104Sdes } 287238104Sdes rr_list = ldns_pkt_answer(packet); 288238104Sdes if (rr_list) { 289238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 290238104Sdes (void) ldns_rr2buffer_wire(buffer, 291238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER); 292238104Sdes } 293238104Sdes } 294238104Sdes rr_list = ldns_pkt_authority(packet); 295238104Sdes if (rr_list) { 296238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 297238104Sdes (void) ldns_rr2buffer_wire(buffer, 298238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY); 299238104Sdes } 300238104Sdes } 301238104Sdes rr_list = ldns_pkt_additional(packet); 302238104Sdes if (rr_list) { 303238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 304238104Sdes (void) ldns_rr2buffer_wire(buffer, 305238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL); 306238104Sdes } 307238104Sdes } 308238104Sdes 309238104Sdes /* add EDNS to additional if it is needed */ 310238104Sdes if (ldns_pkt_edns(packet)) { 311238104Sdes edns_rr = ldns_rr_new(); 312238104Sdes if(!edns_rr) return LDNS_STATUS_MEM_ERR; 313238104Sdes ldns_rr_set_owner(edns_rr, 314238104Sdes ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".")); 315238104Sdes ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT); 316238104Sdes ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet)); 317238104Sdes edata[0] = ldns_pkt_edns_extended_rcode(packet); 318238104Sdes edata[1] = ldns_pkt_edns_version(packet); 319238104Sdes ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet)); 320238104Sdes ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata)); 321238104Sdes /* don't forget to add the edns rdata (if any) */ 322238104Sdes if (packet->_edns_data) 323238104Sdes ldns_rr_push_rdf (edns_rr, packet->_edns_data); 324238104Sdes (void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL); 325238104Sdes /* take the edns rdata back out of the rr before we free rr */ 326238104Sdes if (packet->_edns_data) 327238104Sdes (void)ldns_rr_pop_rdf (edns_rr); 328238104Sdes ldns_rr_free(edns_rr); 329238104Sdes } 330238104Sdes 331238104Sdes /* add TSIG to additional if it is there */ 332238104Sdes if (ldns_pkt_tsig(packet)) { 333238104Sdes (void) ldns_rr2buffer_wire(buffer, 334238104Sdes ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL); 335238104Sdes } 336238104Sdes 337238104Sdes return LDNS_STATUS_OK; 338238104Sdes} 339238104Sdes 340238104Sdesldns_status 341238104Sdesldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size) 342238104Sdes{ 343238104Sdes ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 344238104Sdes ldns_status status; 345238104Sdes *result_size = 0; 346238104Sdes *dest = NULL; 347238104Sdes if(!buffer) return LDNS_STATUS_MEM_ERR; 348238104Sdes 349238104Sdes status = ldns_rdf2buffer_wire(buffer, rdf); 350238104Sdes if (status == LDNS_STATUS_OK) { 351238104Sdes *result_size = ldns_buffer_position(buffer); 352246854Sdes *dest = (uint8_t *) ldns_buffer_export(buffer); 353238104Sdes } 354238104Sdes ldns_buffer_free(buffer); 355238104Sdes return status; 356238104Sdes} 357238104Sdes 358238104Sdesldns_status 359238104Sdesldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size) 360238104Sdes{ 361238104Sdes ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 362238104Sdes ldns_status status; 363238104Sdes *result_size = 0; 364238104Sdes *dest = NULL; 365238104Sdes if(!buffer) return LDNS_STATUS_MEM_ERR; 366238104Sdes 367238104Sdes status = ldns_rr2buffer_wire(buffer, rr, section); 368238104Sdes if (status == LDNS_STATUS_OK) { 369238104Sdes *result_size = ldns_buffer_position(buffer); 370246854Sdes *dest = (uint8_t *) ldns_buffer_export(buffer); 371238104Sdes } 372238104Sdes ldns_buffer_free(buffer); 373238104Sdes return status; 374238104Sdes} 375238104Sdes 376238104Sdesldns_status 377238104Sdesldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size) 378238104Sdes{ 379238104Sdes ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 380238104Sdes ldns_status status; 381238104Sdes *result_size = 0; 382238104Sdes *dest = NULL; 383238104Sdes if(!buffer) return LDNS_STATUS_MEM_ERR; 384238104Sdes 385238104Sdes status = ldns_pkt2buffer_wire(buffer, packet); 386238104Sdes if (status == LDNS_STATUS_OK) { 387238104Sdes *result_size = ldns_buffer_position(buffer); 388246854Sdes *dest = (uint8_t *) ldns_buffer_export(buffer); 389238104Sdes } 390238104Sdes ldns_buffer_free(buffer); 391238104Sdes return status; 392238104Sdes} 393