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 84266114Sdes 85238104Sdesldns_status 86238104Sdesldns_rr2buffer_wire_canonical(ldns_buffer *buffer, 87238104Sdes const ldns_rr *rr, 88238104Sdes int section) 89238104Sdes{ 90238104Sdes uint16_t i; 91238104Sdes uint16_t rdl_pos = 0; 92238104Sdes bool pre_rfc3597 = false; 93238104Sdes switch (ldns_rr_get_type(rr)) { 94238104Sdes case LDNS_RR_TYPE_NS: 95238104Sdes case LDNS_RR_TYPE_MD: 96238104Sdes case LDNS_RR_TYPE_MF: 97238104Sdes case LDNS_RR_TYPE_CNAME: 98238104Sdes case LDNS_RR_TYPE_SOA: 99238104Sdes case LDNS_RR_TYPE_MB: 100238104Sdes case LDNS_RR_TYPE_MG: 101238104Sdes case LDNS_RR_TYPE_MR: 102238104Sdes case LDNS_RR_TYPE_PTR: 103238104Sdes case LDNS_RR_TYPE_HINFO: 104238104Sdes case LDNS_RR_TYPE_MINFO: 105238104Sdes case LDNS_RR_TYPE_MX: 106238104Sdes case LDNS_RR_TYPE_RP: 107238104Sdes case LDNS_RR_TYPE_AFSDB: 108238104Sdes case LDNS_RR_TYPE_RT: 109238104Sdes case LDNS_RR_TYPE_SIG: 110238104Sdes case LDNS_RR_TYPE_PX: 111238104Sdes case LDNS_RR_TYPE_NXT: 112238104Sdes case LDNS_RR_TYPE_NAPTR: 113238104Sdes case LDNS_RR_TYPE_KX: 114238104Sdes case LDNS_RR_TYPE_SRV: 115238104Sdes case LDNS_RR_TYPE_DNAME: 116238104Sdes case LDNS_RR_TYPE_A6: 117238104Sdes case LDNS_RR_TYPE_RRSIG: 118238104Sdes pre_rfc3597 = true; 119238104Sdes break; 120238104Sdes default: 121238104Sdes break; 122238104Sdes } 123238104Sdes 124238104Sdes if (ldns_rr_owner(rr)) { 125238104Sdes (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr)); 126238104Sdes } 127238104Sdes 128238104Sdes if (ldns_buffer_reserve(buffer, 4)) { 129238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); 130238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); 131238104Sdes } 132238104Sdes 133238104Sdes if (section != LDNS_SECTION_QUESTION) { 134238104Sdes if (ldns_buffer_reserve(buffer, 6)) { 135238104Sdes ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); 136238104Sdes /* remember pos for later */ 137238104Sdes rdl_pos = ldns_buffer_position(buffer); 138238104Sdes ldns_buffer_write_u16(buffer, 0); 139238104Sdes } 140238104Sdes for (i = 0; i < ldns_rr_rd_count(rr); i++) { 141238104Sdes if (pre_rfc3597) { 142238104Sdes (void) ldns_rdf2buffer_wire_canonical( 143266114Sdes buffer, ldns_rr_rdf(rr, i)); 144238104Sdes } else { 145238104Sdes (void) ldns_rdf2buffer_wire( 146266114Sdes buffer, ldns_rr_rdf(rr, i)); 147238104Sdes } 148238104Sdes } 149238104Sdes if (rdl_pos != 0) { 150238104Sdes ldns_buffer_write_u16_at(buffer, rdl_pos, 151238104Sdes ldns_buffer_position(buffer) 152238104Sdes - rdl_pos - 2); 153238104Sdes } 154238104Sdes } 155238104Sdes return ldns_buffer_status(buffer); 156238104Sdes} 157238104Sdes 158238104Sdesldns_status 159238104Sdesldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section) 160238104Sdes{ 161238104Sdes uint16_t i; 162238104Sdes uint16_t rdl_pos = 0; 163238104Sdes 164238104Sdes if (ldns_rr_owner(rr)) { 165238104Sdes (void) ldns_dname2buffer_wire(buffer, ldns_rr_owner(rr)); 166238104Sdes } 167238104Sdes 168238104Sdes if (ldns_buffer_reserve(buffer, 4)) { 169238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); 170238104Sdes (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); 171238104Sdes } 172238104Sdes 173238104Sdes if (section != LDNS_SECTION_QUESTION) { 174238104Sdes if (ldns_buffer_reserve(buffer, 6)) { 175238104Sdes ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); 176238104Sdes /* remember pos for later */ 177238104Sdes rdl_pos = ldns_buffer_position(buffer); 178238104Sdes ldns_buffer_write_u16(buffer, 0); 179266114Sdes } 180238104Sdes for (i = 0; i < ldns_rr_rd_count(rr); i++) { 181238104Sdes (void) ldns_rdf2buffer_wire( 182238104Sdes buffer, ldns_rr_rdf(rr, i)); 183238104Sdes } 184238104Sdes if (rdl_pos != 0) { 185238104Sdes ldns_buffer_write_u16_at(buffer, rdl_pos, 186238104Sdes ldns_buffer_position(buffer) 187238104Sdes - rdl_pos - 2); 188238104Sdes } 189238104Sdes } 190238104Sdes return ldns_buffer_status(buffer); 191238104Sdes} 192238104Sdes 193238104Sdesldns_status 194238104Sdesldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) 195238104Sdes{ 196238104Sdes uint16_t i; 197238104Sdes 198238104Sdes /* it must be a sig RR */ 199238104Sdes if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { 200238104Sdes return LDNS_STATUS_ERR; 201238104Sdes } 202238104Sdes 203238104Sdes /* Convert all the rdfs, except the actual signature data 204238104Sdes * rdf number 8 - the last, hence: -1 */ 205238104Sdes for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) { 206266114Sdes (void) ldns_rdf2buffer_wire_canonical(buffer, 207266114Sdes ldns_rr_rdf(rr, i)); 208238104Sdes } 209238104Sdes 210238104Sdes return ldns_buffer_status(buffer); 211238104Sdes} 212238104Sdes 213238104Sdesldns_status 214238104Sdesldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) 215238104Sdes{ 216238104Sdes uint16_t i; 217238104Sdes /* convert all the rdf's */ 218238104Sdes for (i = 0; i < ldns_rr_rd_count(rr); i++) { 219266114Sdes (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i)); 220238104Sdes } 221238104Sdes return ldns_buffer_status(buffer); 222238104Sdes} 223238104Sdes 224238104Sdes/* 225238104Sdes * Copies the packet header data to the buffer in wire format 226238104Sdes */ 227238104Sdesstatic ldns_status 228238104Sdesldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) 229238104Sdes{ 230238104Sdes uint8_t flags; 231238104Sdes uint16_t arcount; 232238104Sdes 233238104Sdes if (ldns_buffer_reserve(buffer, 12)) { 234238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_id(packet)); 235238104Sdes 236238104Sdes flags = ldns_pkt_qr(packet) << 7 237238104Sdes | ldns_pkt_get_opcode(packet) << 3 238238104Sdes | ldns_pkt_aa(packet) << 2 239238104Sdes | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet); 240238104Sdes ldns_buffer_write_u8(buffer, flags); 241238104Sdes 242238104Sdes flags = ldns_pkt_ra(packet) << 7 243238104Sdes /*| ldns_pkt_z(packet) << 6*/ 244238104Sdes | ldns_pkt_ad(packet) << 5 245266114Sdes | ldns_pkt_cd(packet) << 4 246266114Sdes | ldns_pkt_get_rcode(packet); 247238104Sdes ldns_buffer_write_u8(buffer, flags); 248238104Sdes 249238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet)); 250238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet)); 251238104Sdes ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet)); 252238104Sdes /* add EDNS0 and TSIG to additional if they are there */ 253238104Sdes arcount = ldns_pkt_arcount(packet); 254238104Sdes if (ldns_pkt_tsig(packet)) { 255238104Sdes arcount++; 256238104Sdes } 257238104Sdes if (ldns_pkt_edns(packet)) { 258238104Sdes arcount++; 259238104Sdes } 260238104Sdes ldns_buffer_write_u16(buffer, arcount); 261238104Sdes } 262238104Sdes 263238104Sdes return ldns_buffer_status(buffer); 264238104Sdes} 265238104Sdes 266238104Sdesldns_status 267238104Sdesldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) 268238104Sdes{ 269238104Sdes ldns_rr_list *rr_list; 270238104Sdes uint16_t i; 271238104Sdes 272238104Sdes /* edns tmp vars */ 273238104Sdes ldns_rr *edns_rr; 274238104Sdes uint8_t edata[4]; 275238104Sdes 276238104Sdes (void) ldns_hdr2buffer_wire(buffer, packet); 277238104Sdes 278238104Sdes rr_list = ldns_pkt_question(packet); 279238104Sdes if (rr_list) { 280238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 281238104Sdes (void) ldns_rr2buffer_wire(buffer, 282238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION); 283238104Sdes } 284238104Sdes } 285238104Sdes rr_list = ldns_pkt_answer(packet); 286238104Sdes if (rr_list) { 287238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 288238104Sdes (void) ldns_rr2buffer_wire(buffer, 289238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER); 290238104Sdes } 291238104Sdes } 292238104Sdes rr_list = ldns_pkt_authority(packet); 293238104Sdes if (rr_list) { 294238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 295238104Sdes (void) ldns_rr2buffer_wire(buffer, 296238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY); 297238104Sdes } 298238104Sdes } 299238104Sdes rr_list = ldns_pkt_additional(packet); 300238104Sdes if (rr_list) { 301238104Sdes for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 302238104Sdes (void) ldns_rr2buffer_wire(buffer, 303238104Sdes ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL); 304238104Sdes } 305238104Sdes } 306238104Sdes 307238104Sdes /* add EDNS to additional if it is needed */ 308238104Sdes if (ldns_pkt_edns(packet)) { 309238104Sdes edns_rr = ldns_rr_new(); 310238104Sdes if(!edns_rr) return LDNS_STATUS_MEM_ERR; 311238104Sdes ldns_rr_set_owner(edns_rr, 312238104Sdes ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".")); 313238104Sdes ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT); 314238104Sdes ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet)); 315238104Sdes edata[0] = ldns_pkt_edns_extended_rcode(packet); 316238104Sdes edata[1] = ldns_pkt_edns_version(packet); 317238104Sdes ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet)); 318238104Sdes ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata)); 319238104Sdes /* don't forget to add the edns rdata (if any) */ 320238104Sdes if (packet->_edns_data) 321238104Sdes ldns_rr_push_rdf (edns_rr, packet->_edns_data); 322238104Sdes (void)ldns_rr2buffer_wire(buffer, edns_rr, LDNS_SECTION_ADDITIONAL); 323238104Sdes /* take the edns rdata back out of the rr before we free rr */ 324238104Sdes if (packet->_edns_data) 325238104Sdes (void)ldns_rr_pop_rdf (edns_rr); 326238104Sdes ldns_rr_free(edns_rr); 327238104Sdes } 328238104Sdes 329238104Sdes /* add TSIG to additional if it is there */ 330238104Sdes if (ldns_pkt_tsig(packet)) { 331238104Sdes (void) ldns_rr2buffer_wire(buffer, 332238104Sdes ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL); 333238104Sdes } 334238104Sdes 335238104Sdes return LDNS_STATUS_OK; 336238104Sdes} 337238104Sdes 338238104Sdesldns_status 339238104Sdesldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size) 340238104Sdes{ 341238104Sdes ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 342238104Sdes ldns_status status; 343238104Sdes *result_size = 0; 344238104Sdes *dest = NULL; 345238104Sdes if(!buffer) return LDNS_STATUS_MEM_ERR; 346238104Sdes 347238104Sdes status = ldns_rdf2buffer_wire(buffer, rdf); 348238104Sdes if (status == LDNS_STATUS_OK) { 349238104Sdes *result_size = ldns_buffer_position(buffer); 350246854Sdes *dest = (uint8_t *) ldns_buffer_export(buffer); 351238104Sdes } 352238104Sdes ldns_buffer_free(buffer); 353238104Sdes return status; 354238104Sdes} 355238104Sdes 356238104Sdesldns_status 357238104Sdesldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size) 358238104Sdes{ 359238104Sdes ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 360238104Sdes ldns_status status; 361238104Sdes *result_size = 0; 362238104Sdes *dest = NULL; 363238104Sdes if(!buffer) return LDNS_STATUS_MEM_ERR; 364238104Sdes 365238104Sdes status = ldns_rr2buffer_wire(buffer, rr, section); 366238104Sdes if (status == LDNS_STATUS_OK) { 367238104Sdes *result_size = ldns_buffer_position(buffer); 368246854Sdes *dest = (uint8_t *) ldns_buffer_export(buffer); 369238104Sdes } 370238104Sdes ldns_buffer_free(buffer); 371238104Sdes return status; 372238104Sdes} 373238104Sdes 374238104Sdesldns_status 375238104Sdesldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size) 376238104Sdes{ 377238104Sdes ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 378238104Sdes ldns_status status; 379238104Sdes *result_size = 0; 380238104Sdes *dest = NULL; 381238104Sdes if(!buffer) return LDNS_STATUS_MEM_ERR; 382238104Sdes 383238104Sdes status = ldns_pkt2buffer_wire(buffer, packet); 384238104Sdes if (status == LDNS_STATUS_OK) { 385238104Sdes *result_size = ldns_buffer_position(buffer); 386246854Sdes *dest = (uint8_t *) ldns_buffer_export(buffer); 387238104Sdes } 388238104Sdes ldns_buffer_free(buffer); 389238104Sdes return status; 390238104Sdes} 391