1 /* 2 * host2wire.c 3 * 4 * conversion routines from the host to the wire format. 5 * This will usually just a re-ordering of the 6 * data (as we store it in network format) 7 * 8 * a Net::DNS like library for C 9 * 10 * (c) NLnet Labs, 2004-2006 11 * 12 * See the file LICENSE for the license 13 */ 14 15 #include <ldns/config.h> 16 17 #include <ldns/ldns.h> 18 19 ldns_status 20 ldns_dname2buffer_wire(ldns_buffer *buffer, const ldns_rdf *name) 21 { 22 return ldns_dname2buffer_wire_compress(buffer, name, NULL); 23 } 24 25 ldns_status 26 ldns_dname2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *name, ldns_rbtree_t *compression_data) 27 { 28 ldns_rbnode_t *node; 29 uint8_t *data; 30 size_t size; 31 ldns_rdf *label; 32 ldns_rdf *rest; 33 ldns_status s; 34 35 /* If no tree, just add the data */ 36 if(!compression_data) 37 { 38 if (ldns_buffer_reserve(buffer, ldns_rdf_size(name))) 39 { 40 ldns_buffer_write(buffer, ldns_rdf_data(name), ldns_rdf_size(name)); 41 } 42 return ldns_buffer_status(buffer); 43 } 44 45 /* No labels left, write final zero */ 46 if(ldns_dname_label_count(name)==0) 47 { 48 if(ldns_buffer_reserve(buffer,1)) 49 { 50 ldns_buffer_write_u8(buffer, 0); 51 } 52 return ldns_buffer_status(buffer); 53 } 54 55 /* Can we find the name in the tree? */ 56 if((node = ldns_rbtree_search(compression_data, name)) != NULL) 57 { 58 /* Found */ 59 uint16_t position = (uint16_t) (intptr_t) node->data | 0xC000; 60 if (ldns_buffer_reserve(buffer, 2)) 61 { 62 ldns_buffer_write_u16(buffer, position); 63 } 64 return ldns_buffer_status(buffer); 65 } 66 else 67 { 68 /* Not found. Write cache entry, take off first label, write it, */ 69 /* try again with the rest of the name. */ 70 node = LDNS_MALLOC(ldns_rbnode_t); 71 if(!node) 72 { 73 return LDNS_STATUS_MEM_ERR; 74 } 75 if (ldns_buffer_position(buffer) < 16384) { 76 node->key = ldns_rdf_clone(name); 77 node->data = (void *) (intptr_t) ldns_buffer_position(buffer); 78 if(!ldns_rbtree_insert(compression_data,node)) 79 { 80 /* fprintf(stderr,"Name not found but now it's there?\n"); */ 81 } 82 } 83 label = ldns_dname_label(name, 0); 84 rest = ldns_dname_left_chop(name); 85 size = ldns_rdf_size(label) - 1; /* Don't want the final zero */ 86 data = ldns_rdf_data(label); 87 if(ldns_buffer_reserve(buffer, size)) 88 { 89 ldns_buffer_write(buffer, data, size); 90 } 91 ldns_rdf_deep_free(label); 92 s = ldns_dname2buffer_wire_compress(buffer, rest, compression_data); 93 ldns_rdf_deep_free(rest); 94 return s; 95 } 96 } 97 98 ldns_status 99 ldns_rdf2buffer_wire(ldns_buffer *buffer, const ldns_rdf *rdf) 100 { 101 return ldns_rdf2buffer_wire_compress(buffer, rdf, NULL); 102 } 103 104 ldns_status 105 ldns_rdf2buffer_wire_compress(ldns_buffer *buffer, const ldns_rdf *rdf, ldns_rbtree_t *compression_data) 106 { 107 /* If it's a DNAME, call that function to get compression */ 108 if(compression_data && ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) 109 { 110 return ldns_dname2buffer_wire_compress(buffer,rdf,compression_data); 111 } 112 113 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { 114 ldns_buffer_write(buffer, ldns_rdf_data(rdf), ldns_rdf_size(rdf)); 115 } 116 return ldns_buffer_status(buffer); 117 } 118 119 ldns_status 120 ldns_rdf2buffer_wire_canonical(ldns_buffer *buffer, const ldns_rdf *rdf) 121 { 122 size_t i; 123 uint8_t *rdf_data; 124 125 if (ldns_rdf_get_type(rdf) == LDNS_RDF_TYPE_DNAME) { 126 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { 127 rdf_data = ldns_rdf_data(rdf); 128 for (i = 0; i < ldns_rdf_size(rdf); i++) { 129 ldns_buffer_write_u8(buffer, 130 (uint8_t) LDNS_DNAME_NORMALIZE((int)rdf_data[i])); 131 } 132 } 133 } else { 134 /* direct copy for all other types */ 135 if (ldns_buffer_reserve(buffer, ldns_rdf_size(rdf))) { 136 ldns_buffer_write(buffer, 137 ldns_rdf_data(rdf), 138 ldns_rdf_size(rdf)); 139 } 140 } 141 return ldns_buffer_status(buffer); 142 } 143 144 /* convert a rr list to wireformat */ 145 ldns_status 146 ldns_rr_list2buffer_wire(ldns_buffer *buffer,const ldns_rr_list *rr_list) 147 { 148 uint16_t rr_count; 149 uint16_t i; 150 151 rr_count = ldns_rr_list_rr_count(rr_list); 152 for(i = 0; i < rr_count; i++) { 153 (void)ldns_rr2buffer_wire(buffer, ldns_rr_list_rr(rr_list, i), 154 LDNS_SECTION_ANY); 155 } 156 return ldns_buffer_status(buffer); 157 } 158 159 160 ldns_status 161 ldns_rr2buffer_wire_canonical(ldns_buffer *buffer, 162 const ldns_rr *rr, 163 int section) 164 { 165 uint16_t i; 166 uint16_t rdl_pos = 0; 167 bool pre_rfc3597 = false; 168 switch (ldns_rr_get_type(rr)) { 169 case LDNS_RR_TYPE_NS: 170 case LDNS_RR_TYPE_MD: 171 case LDNS_RR_TYPE_MF: 172 case LDNS_RR_TYPE_CNAME: 173 case LDNS_RR_TYPE_SOA: 174 case LDNS_RR_TYPE_MB: 175 case LDNS_RR_TYPE_MG: 176 case LDNS_RR_TYPE_MR: 177 case LDNS_RR_TYPE_PTR: 178 case LDNS_RR_TYPE_HINFO: 179 case LDNS_RR_TYPE_MINFO: 180 case LDNS_RR_TYPE_MX: 181 case LDNS_RR_TYPE_RP: 182 case LDNS_RR_TYPE_AFSDB: 183 case LDNS_RR_TYPE_RT: 184 case LDNS_RR_TYPE_SIG: 185 case LDNS_RR_TYPE_PX: 186 case LDNS_RR_TYPE_NXT: 187 case LDNS_RR_TYPE_NAPTR: 188 case LDNS_RR_TYPE_KX: 189 case LDNS_RR_TYPE_SRV: 190 case LDNS_RR_TYPE_DNAME: 191 case LDNS_RR_TYPE_A6: 192 case LDNS_RR_TYPE_RRSIG: 193 pre_rfc3597 = true; 194 break; 195 default: 196 break; 197 } 198 199 if (ldns_rr_owner(rr)) { 200 (void) ldns_rdf2buffer_wire_canonical(buffer, ldns_rr_owner(rr)); 201 } 202 203 if (ldns_buffer_reserve(buffer, 4)) { 204 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); 205 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); 206 } 207 208 if (section != LDNS_SECTION_QUESTION) { 209 if (ldns_buffer_reserve(buffer, 6)) { 210 ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); 211 /* remember pos for later */ 212 rdl_pos = ldns_buffer_position(buffer); 213 ldns_buffer_write_u16(buffer, 0); 214 } 215 for (i = 0; i < ldns_rr_rd_count(rr); i++) { 216 if (pre_rfc3597) { 217 (void) ldns_rdf2buffer_wire_canonical( 218 buffer, ldns_rr_rdf(rr, i)); 219 } else { 220 (void) ldns_rdf2buffer_wire( 221 buffer, ldns_rr_rdf(rr, i)); 222 } 223 } 224 if (rdl_pos != 0) { 225 ldns_buffer_write_u16_at(buffer, rdl_pos, 226 ldns_buffer_position(buffer) 227 - rdl_pos - 2); 228 } 229 } 230 return ldns_buffer_status(buffer); 231 } 232 233 ldns_status 234 ldns_rr2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr, int section) 235 { 236 return ldns_rr2buffer_wire_compress(buffer,rr,section,NULL); 237 } 238 239 ldns_status 240 ldns_rr2buffer_wire_compress(ldns_buffer *buffer, const ldns_rr *rr, int section, ldns_rbtree_t *compression_data) 241 { 242 uint16_t i; 243 uint16_t rdl_pos = 0; 244 245 if (ldns_rr_owner(rr)) { 246 (void) ldns_dname2buffer_wire_compress(buffer, ldns_rr_owner(rr), compression_data); 247 } 248 249 if (ldns_buffer_reserve(buffer, 4)) { 250 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_type(rr)); 251 (void) ldns_buffer_write_u16(buffer, ldns_rr_get_class(rr)); 252 } 253 254 if (section != LDNS_SECTION_QUESTION) { 255 if (ldns_buffer_reserve(buffer, 6)) { 256 ldns_buffer_write_u32(buffer, ldns_rr_ttl(rr)); 257 /* remember pos for later */ 258 rdl_pos = ldns_buffer_position(buffer); 259 ldns_buffer_write_u16(buffer, 0); 260 } 261 if (LDNS_RR_COMPRESS == 262 ldns_rr_descript(ldns_rr_get_type(rr))->_compress) { 263 264 for (i = 0; i < ldns_rr_rd_count(rr); i++) { 265 (void) ldns_rdf2buffer_wire_compress(buffer, 266 ldns_rr_rdf(rr, i), compression_data); 267 } 268 } else { 269 for (i = 0; i < ldns_rr_rd_count(rr); i++) { 270 (void) ldns_rdf2buffer_wire( 271 buffer, ldns_rr_rdf(rr, i)); 272 } 273 } 274 if (rdl_pos != 0) { 275 ldns_buffer_write_u16_at(buffer, rdl_pos, 276 ldns_buffer_position(buffer) 277 - rdl_pos - 2); 278 } 279 } 280 return ldns_buffer_status(buffer); 281 } 282 283 ldns_status 284 ldns_rrsig2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) 285 { 286 uint16_t i; 287 288 /* it must be a sig RR */ 289 if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) { 290 return LDNS_STATUS_ERR; 291 } 292 293 /* Convert all the rdfs, except the actual signature data 294 * rdf number 8 - the last, hence: -1 */ 295 for (i = 0; i < ldns_rr_rd_count(rr) - 1; i++) { 296 (void) ldns_rdf2buffer_wire_canonical(buffer, 297 ldns_rr_rdf(rr, i)); 298 } 299 300 return ldns_buffer_status(buffer); 301 } 302 303 ldns_status 304 ldns_rr_rdata2buffer_wire(ldns_buffer *buffer, const ldns_rr *rr) 305 { 306 uint16_t i; 307 308 /* convert all the rdf's */ 309 for (i = 0; i < ldns_rr_rd_count(rr); i++) { 310 (void) ldns_rdf2buffer_wire(buffer, ldns_rr_rdf(rr,i)); 311 } 312 return ldns_buffer_status(buffer); 313 } 314 315 /* 316 * Copies the packet header data to the buffer in wire format 317 */ 318 static ldns_status 319 ldns_hdr2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) 320 { 321 uint8_t flags; 322 uint16_t arcount; 323 324 if (ldns_buffer_reserve(buffer, 12)) { 325 ldns_buffer_write_u16(buffer, ldns_pkt_id(packet)); 326 327 flags = ldns_pkt_qr(packet) << 7 328 | ldns_pkt_get_opcode(packet) << 3 329 | ldns_pkt_aa(packet) << 2 330 | ldns_pkt_tc(packet) << 1 | ldns_pkt_rd(packet); 331 ldns_buffer_write_u8(buffer, flags); 332 333 flags = ldns_pkt_ra(packet) << 7 334 /*| ldns_pkt_z(packet) << 6*/ 335 | ldns_pkt_ad(packet) << 5 336 | ldns_pkt_cd(packet) << 4 337 | ldns_pkt_get_rcode(packet); 338 ldns_buffer_write_u8(buffer, flags); 339 340 ldns_buffer_write_u16(buffer, ldns_pkt_qdcount(packet)); 341 ldns_buffer_write_u16(buffer, ldns_pkt_ancount(packet)); 342 ldns_buffer_write_u16(buffer, ldns_pkt_nscount(packet)); 343 /* add EDNS0 and TSIG to additional if they are there */ 344 arcount = ldns_pkt_arcount(packet); 345 if (ldns_pkt_tsig(packet)) { 346 arcount++; 347 } 348 if (ldns_pkt_edns(packet)) { 349 arcount++; 350 } 351 ldns_buffer_write_u16(buffer, arcount); 352 } 353 354 return ldns_buffer_status(buffer); 355 } 356 357 static void 358 compression_node_free(ldns_rbnode_t *node, void *arg) 359 { 360 (void)arg; /* Yes, dear compiler, it is used */ 361 ldns_rdf_deep_free((ldns_rdf *)node->key); 362 LDNS_FREE(node); 363 } 364 365 ldns_status 366 ldns_pkt2buffer_wire(ldns_buffer *buffer, const ldns_pkt *packet) 367 { 368 ldns_rr_list *rr_list; 369 uint16_t i; 370 371 /* edns tmp vars */ 372 ldns_rr *edns_rr; 373 uint8_t edata[4]; 374 375 ldns_rbtree_t *compression_data = ldns_rbtree_create((int (*)(const void *, const void *))ldns_dname_compare); 376 377 (void) ldns_hdr2buffer_wire(buffer, packet); 378 379 rr_list = ldns_pkt_question(packet); 380 if (rr_list) { 381 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 382 (void) ldns_rr2buffer_wire_compress(buffer, 383 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_QUESTION, compression_data); 384 } 385 } 386 rr_list = ldns_pkt_answer(packet); 387 if (rr_list) { 388 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 389 (void) ldns_rr2buffer_wire_compress(buffer, 390 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ANSWER, compression_data); 391 } 392 } 393 rr_list = ldns_pkt_authority(packet); 394 if (rr_list) { 395 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 396 (void) ldns_rr2buffer_wire_compress(buffer, 397 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_AUTHORITY, compression_data); 398 } 399 } 400 rr_list = ldns_pkt_additional(packet); 401 if (rr_list) { 402 for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { 403 (void) ldns_rr2buffer_wire_compress(buffer, 404 ldns_rr_list_rr(rr_list, i), LDNS_SECTION_ADDITIONAL, compression_data); 405 } 406 } 407 408 /* add EDNS to additional if it is needed */ 409 if (ldns_pkt_edns(packet)) { 410 edns_rr = ldns_rr_new(); 411 if(!edns_rr) return LDNS_STATUS_MEM_ERR; 412 ldns_rr_set_owner(edns_rr, 413 ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, ".")); 414 ldns_rr_set_type(edns_rr, LDNS_RR_TYPE_OPT); 415 ldns_rr_set_class(edns_rr, ldns_pkt_edns_udp_size(packet)); 416 edata[0] = ldns_pkt_edns_extended_rcode(packet); 417 edata[1] = ldns_pkt_edns_version(packet); 418 ldns_write_uint16(&edata[2], ldns_pkt_edns_z(packet)); 419 ldns_rr_set_ttl(edns_rr, ldns_read_uint32(edata)); 420 /* don't forget to add the edns rdata (if any) */ 421 if (packet->_edns_data) 422 ldns_rr_push_rdf (edns_rr, packet->_edns_data); 423 (void)ldns_rr2buffer_wire_compress(buffer, edns_rr, LDNS_SECTION_ADDITIONAL, compression_data); 424 /* take the edns rdata back out of the rr before we free rr */ 425 if (packet->_edns_data) 426 (void)ldns_rr_pop_rdf (edns_rr); 427 ldns_rr_free(edns_rr); 428 } 429 430 /* add TSIG to additional if it is there */ 431 if (ldns_pkt_tsig(packet)) { 432 (void) ldns_rr2buffer_wire_compress(buffer, 433 ldns_pkt_tsig(packet), LDNS_SECTION_ADDITIONAL, compression_data); 434 } 435 436 ldns_traverse_postorder(compression_data,compression_node_free,NULL); 437 ldns_rbtree_free(compression_data); 438 439 return LDNS_STATUS_OK; 440 } 441 442 ldns_status 443 ldns_rdf2wire(uint8_t **dest, const ldns_rdf *rdf, size_t *result_size) 444 { 445 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 446 ldns_status status; 447 *result_size = 0; 448 *dest = NULL; 449 if(!buffer) return LDNS_STATUS_MEM_ERR; 450 451 status = ldns_rdf2buffer_wire(buffer, rdf); 452 if (status == LDNS_STATUS_OK) { 453 *result_size = ldns_buffer_position(buffer); 454 *dest = (uint8_t *) ldns_buffer_export(buffer); 455 } 456 ldns_buffer_free(buffer); 457 return status; 458 } 459 460 ldns_status 461 ldns_rr2wire(uint8_t **dest, const ldns_rr *rr, int section, size_t *result_size) 462 { 463 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 464 ldns_status status; 465 *result_size = 0; 466 *dest = NULL; 467 if(!buffer) return LDNS_STATUS_MEM_ERR; 468 469 status = ldns_rr2buffer_wire(buffer, rr, section); 470 if (status == LDNS_STATUS_OK) { 471 *result_size = ldns_buffer_position(buffer); 472 *dest = (uint8_t *) ldns_buffer_export(buffer); 473 } 474 ldns_buffer_free(buffer); 475 return status; 476 } 477 478 ldns_status 479 ldns_pkt2wire(uint8_t **dest, const ldns_pkt *packet, size_t *result_size) 480 { 481 ldns_buffer *buffer = ldns_buffer_new(LDNS_MAX_PACKETLEN); 482 ldns_status status; 483 *result_size = 0; 484 *dest = NULL; 485 if(!buffer) return LDNS_STATUS_MEM_ERR; 486 487 status = ldns_pkt2buffer_wire(buffer, packet); 488 if (status == LDNS_STATUS_OK) { 489 *result_size = ldns_buffer_position(buffer); 490 *dest = (uint8_t *) ldns_buffer_export(buffer); 491 } 492 ldns_buffer_free(buffer); 493 return status; 494 } 495