From: Willem Toorop Date: Wed, 22 May 2013 14:58:29 +0000 (+0000) Subject: Extend output format with ability to print certain given rr types in unknown type... X-Git-Tag: release-1.6.17rc1~102 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5062893c04bfd8adc95ba41459c094b903b878be;p=thirdparty%2Fldns.git Extend output format with ability to print certain given rr types in unknown type format (i.e. rfc3597 format). Thanks Jelte Jansen --- diff --git a/Changelog b/Changelog index f2443963..3e1eec7c 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,8 @@ 1.6.17 + * -u and -U parameter for ldns-read-zone to mark/unmark a RR type + for printing as unknown type + * New output format flag (and accompanying funtions) to print certain + RR's as unknown type * New RR types HIP, NINFO, RKEY, CDS, EUI48, EUI64, URI, CAA and TA. * New RR type TKEY, but without operational practice. * Fix b{32,64}_{ntop,pton} detection and handling. diff --git a/dnssec.c b/dnssec.c index 684d1716..46248a2c 100644 --- a/dnssec.c +++ b/dnssec.c @@ -1338,38 +1338,120 @@ ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name) } bool -ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type) +ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type) { - uint8_t window_block_nr; - uint8_t bitmap_length; - uint16_t cur_type; - uint16_t pos = 0; - uint16_t bit_pos; - uint8_t *data; - - if (nsec_bitmap == NULL) { + uint8_t* dptr; + uint8_t* dend; + + /* From RFC3845 Section 2.1.2: + * + * "The RR type space is split into 256 window blocks, each re- + * presenting the low-order 8 bits of the 16-bit RR type space." + */ + uint8_t window = type >> 8; + uint8_t subtype = type & 0xff; + + if (! bitmap) { return false; } - data = ldns_rdf_data(nsec_bitmap); - while(pos < ldns_rdf_size(nsec_bitmap)) { - window_block_nr = data[pos]; - bitmap_length = data[pos + 1]; - pos += 2; - - for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { - if (ldns_get_bit(&data[pos], bit_pos)) { - cur_type = 256 * (uint16_t) window_block_nr + bit_pos; - if (cur_type == type) { - return true; - } - } - } + assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); - pos += (uint16_t) bitmap_length; + dptr = ldns_rdf_data(bitmap); + dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); + + /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + + * dptr[0] dptr[1] dptr[2:] + */ + while (dptr < dend && dptr[0] <= window) { + + if (dptr[0] == window && subtype / 8 < dptr[1] && + dptr + dptr[1] + 2 <= dend) { + + return dptr[2 + subtype / 8] & (1 << (subtype % 8)); + } + dptr += dptr[1] + 2; /* next window */ } return false; } +ldns_status +ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type) +{ + uint8_t* dptr; + uint8_t* dend; + + /* From RFC3845 Section 2.1.2: + * + * "The RR type space is split into 256 window blocks, each re- + * presenting the low-order 8 bits of the 16-bit RR type space." + */ + uint8_t window = type >> 8; + uint8_t subtype = type & 0xff; + + if (! bitmap) { + return false; + } + assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); + + dptr = ldns_rdf_data(bitmap); + dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); + + /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + + * dptr[0] dptr[1] dptr[2:] + */ + while (dptr < dend && dptr[0] <= window) { + + if (dptr[0] == window && subtype / 8 < dptr[1] && + dptr + dptr[1] + 2 <= dend) { + + dptr[2 + subtype / 8] |= (1 << (subtype % 8)); + return LDNS_STATUS_OK; + } + dptr += dptr[1] + 2; /* next window */ + } + return LDNS_STATUS_TYPE_NOT_IN_BITMAP; +} + +ldns_status +ldns_nsec_bitmap_clear_type(ldns_rdf* bitmap, ldns_rr_type type) +{ + uint8_t* dptr; + uint8_t* dend; + + /* From RFC3845 Section 2.1.2: + * + * "The RR type space is split into 256 window blocks, each re- + * presenting the low-order 8 bits of the 16-bit RR type space." + */ + uint8_t window = type >> 8; + uint8_t subtype = type & 0xff; + + if (! bitmap) { + return false; + } + + assert(ldns_rdf_get_type(bitmap) == LDNS_RDF_TYPE_BITMAP); + + dptr = ldns_rdf_data(bitmap); + dend = ldns_rdf_data(bitmap) + ldns_rdf_size(bitmap); + + /* Type Bitmap = ( Window Block # | Bitmap Length | Bitmap ) + + * dptr[0] dptr[1] dptr[2:] + */ + while (dptr < dend && dptr[0] <= window) { + + if (dptr[0] == window && subtype / 8 < dptr[1] && + dptr + dptr[1] + 2 <= dend) { + + dptr[2 + subtype / 8] &= ~(1 << (subtype % 8)); + return LDNS_STATUS_OK; + } + dptr += dptr[1] + 2; /* next window */ + } + return LDNS_STATUS_TYPE_NOT_IN_BITMAP; +} + + bool ldns_nsec_covers_name(const ldns_rr *nsec, const ldns_rdf *name) { diff --git a/error.c b/error.c index caa40c8c..dc7aee85 100644 --- a/error.c +++ b/error.c @@ -137,6 +137,9 @@ ldns_lookup_table ldns_error_str[] = { { LDNS_STATUS_INVALID_TAG, "Conversion error, a non-zero sequence of US-ASCII letters " "and numbers in lower case expected" }, + { LDNS_STATUS_TYPE_NOT_IN_BITMAP, + "The RR type bitmap rdata field did not have " + "a bit reserved for the specific RR type" }, { 0, NULL } }; diff --git a/examples/ldns-read-zone.1 b/examples/ldns-read-zone.1 index 7d4fd7d9..163b70f6 100644 --- a/examples/ldns-read-zone.1 +++ b/examples/ldns-read-zone.1 @@ -58,6 +58,15 @@ increased by one. When updating a serial number, records of type NSEC, NSEC3, RRSIG and DNSKEY will be skipped when printing the zone. +.TP +\fB-u\fR \fIRR type\fR +Mark \fIRR type\fR for printing in unknown type format + +.TP +\fB-U\fR \fIRR type\fR +Mark \fIRR type\fR for \fBnot\fR printing in unknown type format +When only \fB-U\fR options are given, all types are printed in +unknown type format except the given RR types .TP \fB-v\fR diff --git a/examples/ldns-read-zone.c b/examples/ldns-read-zone.c index efe187e6..f26876fa 100644 --- a/examples/ldns-read-zone.c +++ b/examples/ldns-read-zone.c @@ -15,6 +15,44 @@ #include +void print_usage(const char* progname) +{ + printf("Usage: %s [OPTIONS] \n", progname); + printf("\tReads the zonefile and prints it.\n"); + printf("\tThe RR count of the zone is printed to stderr.\n"); + printf("\t-b include bubblebabble of DS's.\n"); + printf("\t-0 zeroize timestamps and signature in RRSIG records.\n"); + printf("\t-c canonicalize all rrs in the zone.\n"); + printf("\t-d only show DNSSEC data from the zone\n"); + printf("\t-h show this text\n"); + printf("\t-n do not print the SOA record\n"); + printf("\t-p prepend SOA serial with spaces so" + " it takes exactly ten characters.\n"); + printf("\t-s strip DNSSEC data from the zone\n"); + printf("\t-S [[+|-] | YYYYMMDDxx | " + " unixtime ]\n" + "\t\tSet serial number to or," + " when preceded by a sign,\n" + "\t\toffset the existing number with " + ". With YYYYMMDDxx\n" + "\t\tthe serial is formatted as a datecounter" + ", and with unixtime as the\n" + "\t\tnumber of seconds since 1-1-1970." + " However, on serial number" + "\n\t\tdecrease, +1 is used in stead" + ". (implies -s)\n"); + printf("\t-u \n"); + printf("\t\tMark for printing in unknown type format\n"); + printf("\t-U \n"); + printf("\t\tMark for not printing in unknown type format\n"); + printf("\t\tWhen only -U options are given, all types are printed in" + "\n\t\tunknown type format except the given RR types\n"); + printf("\t-v shows the version and exits\n"); + printf("\t-z sort the zone (implies -c).\n"); + printf("\nif no file is given standard input is read\n"); + exit(EXIT_SUCCESS); +} + int main(int argc, char **argv) { @@ -33,22 +71,21 @@ main(int argc, char **argv) ldns_rr_list *stripped_list; ldns_rr *cur_rr; ldns_rr_type cur_rr_type; - ldns_output_format fmt = { - ldns_output_format_default->flags, - ldns_output_format_default->data - }; + ldns_output_format_storage fmt_storage; + ldns_output_format* fmt = ldns_output_format_init(&fmt_storage); + ldns_soa_serial_increment_func_t soa_serial_increment_func = NULL; int soa_serial_increment_func_data = 0; - while ((c = getopt(argc, argv, "0bcdhnpsvzS:")) != -1) { + while ((c = getopt(argc, argv, "0bcdhnpsu:U:vzS:")) != -1) { switch(c) { case 'b': - fmt.flags |= + fmt->flags |= ( LDNS_COMMENT_BUBBLEBABBLE | LDNS_COMMENT_FLAGS ); break; case '0': - fmt.flags |= LDNS_FMT_ZEROIZE_RRSIGS; + fmt->flags |= LDNS_FMT_ZEROIZE_RRSIGS; break; case 'c': canonicalize = true; @@ -60,40 +97,13 @@ main(int argc, char **argv) } break; case 'h': - printf("Usage: %s [OPTIONS] \n", argv[0]); - printf("\tReads the zonefile and prints it.\n"); - printf("\tThe RR count of the zone is printed to stderr.\n"); - printf("\t-b include bubblebabble of DS's.\n"); - printf("\t-0 zeroize timestamps and signature in RRSIG records.\n"); - printf("\t-c canonicalize all rrs in the zone.\n"); - printf("\t-d only show DNSSEC data from the zone\n"); - printf("\t-h show this text\n"); - printf("\t-n do not print the SOA record\n"); - printf("\t-p prepend SOA serial with spaces so" - " it takes exactly ten characters.\n"); - printf("\t-s strip DNSSEC data from the zone\n"); - printf("\t-S [[+|-] | YYYYMMDDxx | " - " unixtime ]\n" - "\t\tSet serial number to or," - " when preceded by a sign,\n" - "\t\toffset the existing number with " - ". With YYYYMMDDxx\n" - "\t\tthe serial is formatted as a datecounter" - ", and with unixtime as the\n" - "\t\tnumber of seconds since 1-1-1970." - " However, on serial number" - "\n\t\tdecrease, +1 is used in stead" - ". (implies -s)\n"); - printf("\t-v shows the version and exits\n"); - printf("\t-z sort the zone (implies -c).\n"); - printf("\nif no file is given standard input is read\n"); - exit(EXIT_SUCCESS); + print_usage("ldns-read-zone"); break; case 'n': print_soa = false; break; case 'p': - fmt.flags |= LDNS_FMT_PAD_SOA_SERIAL; + fmt->flags |= LDNS_FMT_PAD_SOA_SERIAL; break; case 's': strip = true; @@ -101,6 +111,38 @@ main(int argc, char **argv) fprintf(stderr, "Warning: stripping both DNSSEC and non-DNSSEC records. Output will be sparse.\n"); } break; + case 'u': + s = ldns_output_format_set_type(fmt, + ldns_get_rr_type_by_name(optarg)); + if (s != LDNS_STATUS_OK) { + fprintf( stderr + , "Cannot set rr type %s " + "in output format to " + "print as unknown type: %s\n" + , ldns_rr_descript( + ldns_get_rr_type_by_name(optarg) + )->_name + , ldns_get_errorstr_by_id(s) + ); + exit(EXIT_FAILURE); + } + break; + case 'U': + s = ldns_output_format_clear_type(fmt, + ldns_get_rr_type_by_name(optarg)); + if (s != LDNS_STATUS_OK) { + fprintf( stderr + , "Cannot set rr type %s " + "in output format to not " + "print as unknown type: %s\n" + , ldns_rr_descript( + ldns_get_rr_type_by_name(optarg) + )->_name + , ldns_get_errorstr_by_id(s) + ); + exit(EXIT_FAILURE); + } + break; case 'v': printf("read zone version %s (ldns version %s)\n", LDNS_VERSION, ldns_version()); exit(EXIT_SUCCESS); @@ -218,9 +260,9 @@ main(int argc, char **argv) , soa_serial_increment_func_data ); } - ldns_rr_print_fmt(stdout, &fmt, ldns_zone_soa(z)); + ldns_rr_print_fmt(stdout, fmt, ldns_zone_soa(z)); } - ldns_rr_list_print_fmt(stdout, &fmt, ldns_zone_rrs(z)); + ldns_rr_list_print_fmt(stdout, fmt, ldns_zone_rrs(z)); ldns_zone_deep_free(z); diff --git a/examples/ldns-signzone.c b/examples/ldns-signzone.c index 25ece3a6..5eaa3cc0 100644 --- a/examples/ldns-signzone.c +++ b/examples/ldns-signzone.c @@ -368,9 +368,8 @@ main(int argc, char *argv[]) char *prog = strdup(argv[0]); ldns_status result; - ldns_output_format fmt = { ldns_output_format_default->flags, NULL }; - void **hashmap = NULL; - + ldns_output_format_storage fmt_st; + ldns_output_format* fmt = ldns_output_format_init(&fmt_st); inception = 0; expiration = 0; @@ -389,11 +388,10 @@ main(int argc, char *argv[]) } break; case 'b': - fmt.flags |= LDNS_COMMENT_BUBBLEBABBLE; - fmt.flags |= LDNS_COMMENT_FLAGS; - fmt.flags |= LDNS_COMMENT_NSEC3_CHAIN; - fmt.flags |= LDNS_COMMENT_LAYOUT; - hashmap = &fmt.data; + ldns_output_format_set(fmt, LDNS_COMMENT_FLAGS + | LDNS_COMMENT_LAYOUT + | LDNS_COMMENT_NSEC3_CHAIN + | LDNS_COMMENT_BUBBLEBABBLE); break; case 'd': add_keys = false; @@ -767,7 +765,7 @@ main(int argc, char *argv[]) nsec3_salt_length, nsec3_salt, signflags, - (ldns_rbtree_t**) hashmap); + &fmt_st.hashmap); } else { result = ldns_dnssec_zone_sign_flg(signed_zone, added_rrs, @@ -796,7 +794,7 @@ main(int argc, char *argv[]) outputfile_name, strerror(errno)); } else { ldns_dnssec_zone_print_fmt( - outputfile, &fmt, signed_zone); + outputfile, fmt, signed_zone); fclose(outputfile); } } diff --git a/higher.c b/higher.c index 990fb6af..25ce3585 100644 --- a/higher.c +++ b/higher.c @@ -303,39 +303,21 @@ ldns_getaddrinfo(ldns_resolver *res, ldns_rdf *node, ldns_rr_class c, bool ldns_nsec_type_check(ldns_rr *nsec, ldns_rr_type t) { - /* does the nsec cover the t given? */ - /* copied from host2str.c line 465: ldns_rdf2buffer_str_nsec */ - uint8_t window_block_nr; - uint8_t bitmap_length; - uint16_t type; - uint16_t pos = 0; - uint16_t bit_pos; - ldns_rdf *nsec_type_list = ldns_rr_rdf(nsec, 1); - uint8_t *data; - - if (nsec_type_list == NULL) { - return false; + switch (ldns_rr_get_type(nsec)) { + case LDNS_RR_TYPE_NSEC : if (ldns_rr_rd_count(nsec) < 2) { + return false; + } + return ldns_nsec_bitmap_covers_type( + ldns_rr_rdf(nsec, 1), t); + + case LDNS_RR_TYPE_NSEC3 : if (ldns_rr_rd_count(nsec) < 6) { + return false; + } + return ldns_nsec_bitmap_covers_type( + ldns_rr_rdf(nsec, 5), t); + + default : return false; } - data = ldns_rdf_data(nsec_type_list); - - while(pos < ldns_rdf_size(nsec_type_list)) { - window_block_nr = data[pos]; - bitmap_length = data[pos + 1]; - pos += 2; - - for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { - if (ldns_get_bit(&data[pos], bit_pos)) { - type = 256 * (uint16_t) window_block_nr + bit_pos; - - if ((ldns_rr_type)type == t) { - /* we have a winner */ - return true; - } - } - } - pos += (uint16_t) bitmap_length; - } - return false; } void @@ -358,3 +340,4 @@ ldns_print_rr_rdf(FILE *fp, ldns_rr *r, int rdfnum, ...) } va_end(va_rdf); } + diff --git a/host2str.c b/host2str.c index 08d62b5b..86b7f1e8 100644 --- a/host2str.c +++ b/host2str.c @@ -130,6 +130,55 @@ const ldns_output_format ldns_output_format_bubblebabble_record = { const ldns_output_format *ldns_output_format_bubblebabble = &ldns_output_format_bubblebabble_record; +static bool +ldns_output_format_covers_type(const ldns_output_format* fmt, ldns_rr_type t) +{ + return fmt && (fmt->flags & LDNS_FMT_RFC3597) && + ((ldns_output_format_storage*)fmt)->bitmap && + ldns_nsec_bitmap_covers_type( + ((ldns_output_format_storage*)fmt)->bitmap, t); +} + +ldns_status +ldns_output_format_set_type(ldns_output_format* fmt, ldns_rr_type t) +{ + ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; + ldns_status s; + + assert(fmt != NULL); + + if (!(fmt_st->flags & LDNS_FMT_RFC3597)) { + ldns_output_format_set(fmt, LDNS_FMT_RFC3597); + } + if (! fmt_st->bitmap) { + s = ldns_rdf_bitmap_known_rr_types_space(&fmt_st->bitmap); + if (s != LDNS_STATUS_OK) { + return s; + } + } + return ldns_nsec_bitmap_set_type(fmt_st->bitmap, t); +} + +ldns_status +ldns_output_format_clear_type(ldns_output_format* fmt, ldns_rr_type t) +{ + ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; + ldns_status s; + + assert(fmt != NULL); + + if (!(fmt_st->flags & LDNS_FMT_RFC3597)) { + ldns_output_format_set(fmt, LDNS_FMT_RFC3597); + } + if (! fmt_st->bitmap) { + s = ldns_rdf_bitmap_known_rr_types(&fmt_st->bitmap); + if (s != LDNS_STATUS_OK) { + return s; + } + } + return ldns_nsec_bitmap_clear_type(fmt_st->bitmap, t); +} + ldns_status ldns_pkt_opcode2buffer_str(ldns_buffer *output, ldns_pkt_opcode opcode) { @@ -463,18 +512,27 @@ ldns_rdf2buffer_str_hex(ldns_buffer *output, const ldns_rdf *rdf) } ldns_status -ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf) +ldns_rdf2buffer_str_type_fmt(ldns_buffer *output, + const ldns_output_format* fmt, const ldns_rdf *rdf) { uint16_t data = ldns_read_uint16(ldns_rdf_data(rdf)); - const ldns_rr_descriptor *descriptor; - descriptor = ldns_rr_descript(data); - if (descriptor && descriptor->_name) { - ldns_buffer_printf(output, "%s", descriptor->_name); + if (! ldns_output_format_covers_type(fmt, data) && + ldns_rr_descript(data) && + ldns_rr_descript(data)->_name) { + + ldns_buffer_printf(output, "%s",ldns_rr_descript(data)->_name); } else { ldns_buffer_printf(output, "TYPE%u", data); } - return ldns_buffer_status(output); + return ldns_buffer_status(output); +} + +ldns_status +ldns_rdf2buffer_str_type(ldns_buffer *output, const ldns_rdf *rdf) +{ + return ldns_rdf2buffer_str_type_fmt(output, + ldns_output_format_default, rdf); } ldns_status @@ -780,7 +838,8 @@ ldns_rdf2buffer_str_wks(ldns_buffer *output, const ldns_rdf *rdf) } ldns_status -ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) +ldns_rdf2buffer_str_nsec_fmt(ldns_buffer *output, + const ldns_output_format* fmt, const ldns_rdf *rdf) { /* Note: this code is duplicated in higher.c in * ldns_nsec_type_check() function @@ -791,7 +850,6 @@ ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) uint16_t pos = 0; uint16_t bit_pos; uint8_t *data = ldns_rdf_data(rdf); - const ldns_rr_descriptor *descriptor; while((size_t)(pos + 2) < ldns_rdf_size(rdf)) { window_block_nr = data[pos]; @@ -801,16 +859,19 @@ ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) return LDNS_STATUS_WIRE_RDATA_ERR; } for (bit_pos = 0; bit_pos < (bitmap_length) * 8; bit_pos++) { - if (ldns_get_bit(&data[pos], bit_pos)) { - type = 256 * (uint16_t) window_block_nr + bit_pos; - descriptor = ldns_rr_descript(type); + if (! ldns_get_bit(&data[pos], bit_pos)) { + continue; + } + type = 256 * (uint16_t) window_block_nr + bit_pos; - if (descriptor && descriptor->_name) { - ldns_buffer_printf(output, "%s ", - descriptor->_name); - } else { - ldns_buffer_printf(output, "TYPE%u ", type); - } + if (! ldns_output_format_covers_type(fmt, type) && + ldns_rr_descript(type) && + ldns_rr_descript(type)->_name){ + + ldns_buffer_printf(output, "%s ", + ldns_rr_descript(type)->_name); + } else { + ldns_buffer_printf(output, "TYPE%u ", type); } } pos += (uint16_t) bitmap_length; @@ -818,6 +879,13 @@ ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) return ldns_buffer_status(output); } +ldns_status +ldns_rdf2buffer_str_nsec(ldns_buffer *output, const ldns_rdf *rdf) +{ + return ldns_rdf2buffer_str_nsec_fmt(output, + ldns_output_format_default, rdf); +} + ldns_status ldns_rdf2buffer_str_nsec3_salt(ldns_buffer *output, const ldns_rdf *rdf) { @@ -1202,7 +1270,8 @@ ldns_rdf2buffer_str_multi_str(ldns_buffer *output, const ldns_rdf *rdf) } ldns_status -ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) +ldns_rdf2buffer_str_fmt(ldns_buffer *buffer, + const ldns_output_format* fmt, const ldns_rdf *rdf) { ldns_status res = LDNS_STATUS_OK; @@ -1251,13 +1320,13 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) res = ldns_rdf2buffer_str_hex(buffer, rdf); break; case LDNS_RDF_TYPE_NSEC: - res = ldns_rdf2buffer_str_nsec(buffer, rdf); + res = ldns_rdf2buffer_str_nsec_fmt(buffer, fmt, rdf); break; case LDNS_RDF_TYPE_NSEC3_SALT: res = ldns_rdf2buffer_str_nsec3_salt(buffer, rdf); break; case LDNS_RDF_TYPE_TYPE: - res = ldns_rdf2buffer_str_type(buffer, rdf); + res = ldns_rdf2buffer_str_type_fmt(buffer, fmt, rdf); break; case LDNS_RDF_TYPE_CLASS: res = ldns_rdf2buffer_str_class(buffer, rdf); @@ -1326,6 +1395,12 @@ ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) return res; } +ldns_status +ldns_rdf2buffer_str(ldns_buffer *buffer, const ldns_rdf *rdf) +{ + return ldns_rdf2buffer_str_fmt(buffer,ldns_output_format_default,rdf); +} + static ldns_rdf * ldns_b32_ext2dname(const ldns_rdf *rdf) { @@ -1353,18 +1428,45 @@ ldns_b32_ext2dname(const ldns_rdf *rdf) return NULL; } +static ldns_status +ldns_rr2buffer_str_rfc3597(ldns_buffer *output, const ldns_rr *rr) +{ + size_t total_rdfsize = 0; + size_t i, j; + + ldns_buffer_printf(output, "TYPE%u\t", ldns_rr_get_type(rr)); + for (i = 0; i < ldns_rr_rd_count(rr); i++) { + total_rdfsize += ldns_rdf_size(ldns_rr_rdf(rr, i)); + } + if (total_rdfsize == 0) { + ldns_buffer_printf(output, "\\# 0\n"); + return ldns_buffer_status(output); + } + ldns_buffer_printf(output, "\\# %d ", total_rdfsize); + for (i = 0; i < ldns_rr_rd_count(rr); i++) { + for (j = 0; j < ldns_rdf_size(ldns_rr_rdf(rr, i)); j++) { + ldns_buffer_printf(output, "%.2x", + ldns_rdf_data(ldns_rr_rdf(rr, i))[j]); + } + } + ldns_buffer_printf(output, "\n"); + return ldns_buffer_status(output); +} + ldns_status ldns_rr2buffer_str_fmt(ldns_buffer *output, const ldns_output_format *fmt, const ldns_rr *rr) { uint16_t i, flags; ldns_status status = LDNS_STATUS_OK; + ldns_output_format_storage* fmt_st = (ldns_output_format_storage*)fmt; - if (fmt == NULL) { - fmt = ldns_output_format_default; + if (fmt_st == NULL) { + fmt_st = (ldns_output_format_storage*) + ldns_output_format_default; } if (!rr) { - if (LDNS_COMMENT_NULLS & fmt->flags) { + if (LDNS_COMMENT_NULLS & fmt_st->flags) { ldns_buffer_printf(output, "; (null)\n"); } return ldns_buffer_status(output); @@ -1388,6 +1490,9 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, } ldns_buffer_printf(output, "\t"); + if (ldns_output_format_covers_type(fmt, ldns_rr_get_type(rr))) { + return ldns_rr2buffer_str_rfc3597(output, rr); + } status = ldns_rr_type2buffer_str(output, ldns_rr_get_type(rr)); if (status != LDNS_STATUS_OK) { return status; @@ -1401,7 +1506,7 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, for (i = 0; i < ldns_rr_rd_count(rr); i++) { /* ldns_rdf2buffer_str handles NULL input fine! */ - if ((fmt->flags & LDNS_FMT_ZEROIZE_RRSIGS) && + if ((fmt_st->flags & LDNS_FMT_ZEROIZE_RRSIGS) && (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) && ((/* inception */ i == 4 && ldns_rdf_get_type(ldns_rr_rdf(rr, 4)) == @@ -1415,7 +1520,7 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, ldns_buffer_printf(output, "(null)"); status = ldns_buffer_status(output); - } else if ((fmt->flags & LDNS_FMT_PAD_SOA_SERIAL) && + } else if ((fmt_st->flags & LDNS_FMT_PAD_SOA_SERIAL) && (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) && /* serial */ i == 2 && ldns_rdf_get_type(ldns_rr_rdf(rr, 2)) == @@ -1425,8 +1530,8 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, ldns_rdf_data(ldns_rr_rdf(rr, 2)))); status = ldns_buffer_status(output); } else { - status = ldns_rdf2buffer_str(output, - ldns_rr_rdf(rr, i)); + status = ldns_rdf2buffer_str_fmt(output, + fmt, ldns_rr_rdf(rr, i)); } if(status != LDNS_STATUS_OK) return status; @@ -1439,137 +1544,120 @@ ldns_rr2buffer_str_fmt(ldns_buffer *output, * getting here */ if (ldns_rr_rd_count(rr) > 0) { switch (ldns_rr_get_type(rr)) { - case LDNS_RR_TYPE_DNSKEY: - /* if ldns_rr_rd_count(rr) > 0 - then ldns_rr_rdf(rr, 0) exists! */ - if (! (fmt->flags & LDNS_COMMENT_KEY)) { - break; - } - flags = ldns_rdf2native_int16( - ldns_rr_rdf(rr, 0)); - ldns_buffer_printf(output, " ;{"); - if (fmt->flags & LDNS_COMMENT_KEY_ID) { - ldns_buffer_printf(output, "id = %u", - (unsigned int) - ldns_calc_keytag(rr)); - } - if ((fmt->flags & LDNS_COMMENT_KEY_TYPE) - && (flags & LDNS_KEY_ZONE_KEY)){ - if (flags & LDNS_KEY_SEP_KEY) { - ldns_buffer_printf( - output, " (ksk)"); - } - else { - ldns_buffer_printf( - output, " (zsk)"); - } - if (fmt->flags & LDNS_COMMENT_KEY_SIZE){ - ldns_buffer_printf( - output, ", "); - } - } else if (fmt->flags - & (LDNS_COMMENT_KEY_ID - |LDNS_COMMENT_KEY_SIZE)) { - ldns_buffer_printf( output, ", "); + case LDNS_RR_TYPE_DNSKEY: + /* if ldns_rr_rd_count(rr) > 0 + then ldns_rr_rdf(rr, 0) exists! */ + if (! (fmt_st->flags & LDNS_COMMENT_KEY)) { + break; + } + flags = ldns_rdf2native_int16(ldns_rr_rdf(rr, 0)); + ldns_buffer_printf(output, " ;{"); + if (fmt_st->flags & LDNS_COMMENT_KEY_ID) { + ldns_buffer_printf(output, "id = %u", + (unsigned int) ldns_calc_keytag(rr)); + } + if ((fmt_st->flags & LDNS_COMMENT_KEY_TYPE) && + (flags & LDNS_KEY_ZONE_KEY)){ + + if (flags & LDNS_KEY_SEP_KEY) { + ldns_buffer_printf(output, " (ksk)"); + } else { + ldns_buffer_printf(output, " (zsk)"); } - if (fmt->flags & LDNS_COMMENT_KEY_SIZE) { - ldns_buffer_printf(output, "size = %db", - ldns_rr_dnskey_key_size(rr)); + if (fmt_st->flags & LDNS_COMMENT_KEY_SIZE){ + ldns_buffer_printf(output, ", "); } - ldns_buffer_printf(output, "}"); - break; - case LDNS_RR_TYPE_RRSIG: - if ((fmt->flags & LDNS_COMMENT_KEY) - && (fmt->flags - & LDNS_COMMENT_RRSIGS) - && ldns_rr_rdf(rr, 6) != NULL) { - ldns_buffer_printf(output - , " ;{id = %d}" - , ldns_rdf2native_int16( + } else if (fmt_st->flags + & (LDNS_COMMENT_KEY_ID + |LDNS_COMMENT_KEY_SIZE)) { + ldns_buffer_printf( output, ", "); + } + if (fmt_st->flags & LDNS_COMMENT_KEY_SIZE) { + ldns_buffer_printf(output, "size = %db", + ldns_rr_dnskey_key_size(rr)); + } + ldns_buffer_printf(output, "}"); + break; + case LDNS_RR_TYPE_RRSIG: + if ((fmt_st->flags & LDNS_COMMENT_KEY) + && (fmt_st->flags& LDNS_COMMENT_RRSIGS) + && ldns_rr_rdf(rr, 6) != NULL) { + ldns_buffer_printf(output, " ;{id = %d}", + ldns_rdf2native_int16( ldns_rr_rdf(rr, 6))); + } + break; + case LDNS_RR_TYPE_DS: + if ((fmt_st->flags & LDNS_COMMENT_BUBBLEBABBLE) && + ldns_rr_rdf(rr, 3) != NULL) { + + uint8_t *data = ldns_rdf_data( + ldns_rr_rdf(rr, 3)); + size_t len = ldns_rdf_size(ldns_rr_rdf(rr, 3)); + char *babble = ldns_bubblebabble(data, len); + if(babble) { + ldns_buffer_printf(output, + " ;{%s}", babble); } + LDNS_FREE(babble); + } + break; + case LDNS_RR_TYPE_NSEC3: + if (! (fmt_st->flags & LDNS_COMMENT_FLAGS) && + ! (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN)) { break; - case LDNS_RR_TYPE_DS: - if ((fmt->flags & LDNS_COMMENT_BUBBLEBABBLE) - && ldns_rr_rdf(rr, 3) != NULL) { - uint8_t *data = ldns_rdf_data( - ldns_rr_rdf(rr, 3)); - size_t len = ldns_rdf_size( - ldns_rr_rdf(rr, 3)); - char *babble = ldns_bubblebabble( - data, len); - if(babble) { - ldns_buffer_printf(output - , " ;{%s}", babble); - } - LDNS_FREE(babble); + } + ldns_buffer_printf(output, " ;{"); + if ((fmt_st->flags & LDNS_COMMENT_FLAGS)) { + if (ldns_nsec3_optout(rr)) { + ldns_buffer_printf(output, + " flags: optout"); + } else { + ldns_buffer_printf(output," flags: -"); } - break; - case LDNS_RR_TYPE_NSEC3: - if (! (fmt->flags & LDNS_COMMENT_FLAGS) && - ! (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN)) { - break; + if (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN && + fmt_st->hashmap != NULL) { + ldns_buffer_printf(output, ", "); } - ldns_buffer_printf(output, " ;{"); - if ((fmt->flags & LDNS_COMMENT_FLAGS)) { - if (ldns_nsec3_optout(rr)) { - ldns_buffer_printf(output, - " flags: optout"); - } else { + } + if (fmt_st->flags & LDNS_COMMENT_NSEC3_CHAIN && + fmt_st->hashmap != NULL) { + ldns_rbnode_t *node; + ldns_rdf *key = ldns_dname_label( + ldns_rr_owner(rr), 0); + if (key) { + node = ldns_rbtree_search( + fmt_st->hashmap, + (void *) key); + if (node->data) { ldns_buffer_printf(output, - " flags: -"); - } - if (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN - && fmt->data != NULL) { - ldns_buffer_printf(output, ", "); + "from: "); + (void) ldns_rdf2buffer_str( + output, + (ldns_rdf*)node->data); } + ldns_rdf_free(key); } - if (fmt->flags & LDNS_COMMENT_NSEC3_CHAIN - && fmt->data != NULL) { - ldns_rbnode_t *node; - ldns_rdf *key = ldns_dname_label( - ldns_rr_owner(rr), 0); - if (key) { - node = ldns_rbtree_search( - (ldns_rbtree_t *) - fmt->data, - (void *) key); - if (node->data) { - ldns_buffer_printf( - output, - "from: "); - (void) - ldns_rdf2buffer_str( - output, - (ldns_rdf *) - node->data); - } - ldns_rdf_free(key); - } - key = ldns_b32_ext2dname( + key = ldns_b32_ext2dname( ldns_nsec3_next_owner(rr)); - if (key) { - node = ldns_rbtree_search( - (ldns_rbtree_t *) - fmt->data, - (void *) key); - if (node->data) { - ldns_buffer_printf( - output, - " to: "); - (void) - ldns_rdf2buffer_str( - output, - (ldns_rdf *) - node->data); - } - ldns_rdf_free(key); + if (key) { + node = ldns_rbtree_search( + fmt_st->hashmap, + (void *) key); + if (node->data) { + ldns_buffer_printf(output, + " to: "); + (void) ldns_rdf2buffer_str( + output, + (ldns_rdf*)node->data); } + ldns_rdf_free(key); } - ldns_buffer_printf(output, "}"); - break; - default: - break; + } + ldns_buffer_printf(output, "}"); + break; + default: + break; } } diff --git a/ldns/dnssec.h b/ldns/dnssec.h index 34f63714..3e992c68 100644 --- a/ldns/dnssec.h +++ b/ldns/dnssec.h @@ -364,12 +364,30 @@ ldns_rdf *ldns_nsec3_bitmap(const ldns_rr *nsec3_rr); ldns_rdf *ldns_nsec3_hash_name_frm_nsec3(const ldns_rr *nsec, ldns_rdf *name); /** - * Checks coverage of NSEC RR type bitmap - * \param[in] nsec_bitmap The NSEC bitmap rdata field to check - * \param[in] type The type to check - * \return true if the NSEC RR covers the type + * Check if RR type t is enumerated and set in the RR type bitmap rdf. + * \param[in] bitmap the RR type bitmap rdf to look in + * \param[in] type the type to check for + * \return true when t is found and set, otherwise return false */ -bool ldns_nsec_bitmap_covers_type(const ldns_rdf *nsec_bitmap, ldns_rr_type type); +bool ldns_nsec_bitmap_covers_type(const ldns_rdf* bitmap, ldns_rr_type type); + +/** + * Check if RR type t is enumerated in the type bitmap rdf and sets the bit. + * \param[in] bitmap the RR type bitmap rdf to look in + * \param[in] type the type to for which the bit to set + * \return LDNS_STATUS_OK on success. LDNS_STATUS_TYPE_NOT_IN_BITMAP is + * returned when the bitmap does not contain the bit to set. + */ +ldns_status ldns_nsec_bitmap_set_type(ldns_rdf* bitmap, ldns_rr_type type); + +/** + * Check if RR type t is enumerated in the type bitmap rdf and sets the bit. + * \param[in] bitmap the RR type bitmap rdf to look in + * \param[in] type the type to for which the bit to set + * \return LDNS_STATUS_OK on success. LDNS_STATUS_TYPE_NOT_IN_BITMAP is + * returned when the bitmap does not contain the bit to set. + */ +ldns_status ldns_nsec_bitmap_clear_type(ldns_rdf* rdf, ldns_rr_type t); /** * Checks coverage of NSEC(3) RR name span diff --git a/ldns/error.h b/ldns/error.h index d37f7467..e70f8d6a 100644 --- a/ldns/error.h +++ b/ldns/error.h @@ -123,7 +123,8 @@ enum ldns_enum_status { LDNS_STATUS_INVALID_EUI48, LDNS_STATUS_INVALID_EUI64, LDNS_STATUS_WIRE_RDATA_ERR, - LDNS_STATUS_INVALID_TAG + LDNS_STATUS_INVALID_TAG, + LDNS_STATUS_TYPE_NOT_IN_BITMAP, }; typedef enum ldns_enum_status ldns_status; diff --git a/ldns/host2str.h b/ldns/host2str.h index 6b5fcd03..4c7d1452 100644 --- a/ldns/host2str.h +++ b/ldns/host2str.h @@ -43,29 +43,35 @@ extern "C" { * Represent a NULL pointer (in stead of a pointer to a ldns_rr as "; (null)" * as opposed to outputting nothing at all in such a case. */ -#define LDNS_COMMENT_NULLS 0x0001 +/* Flag Name Flag Nr. Has data associated + ---------------------------------------------------------------------*/ +#define LDNS_COMMENT_NULLS (1 << 0) /** Show key id with DNSKEY RR's as comment */ -#define LDNS_COMMENT_KEY_ID 0x0002 +#define LDNS_COMMENT_KEY_ID (1 << 1) /** Show if a DNSKEY is a ZSK or KSK as comment */ -#define LDNS_COMMENT_KEY_TYPE 0x0004 +#define LDNS_COMMENT_KEY_TYPE (1 << 2) /** Show DNSKEY key size as comment */ -#define LDNS_COMMENT_KEY_SIZE 0x0008 -/** Show key id, type and size as comment for DNSKEY RR's */ -#define LDNS_COMMENT_KEY (LDNS_COMMENT_KEY_ID \ - |LDNS_COMMENT_KEY_TYPE\ - |LDNS_COMMENT_KEY_SIZE) +#define LDNS_COMMENT_KEY_SIZE (1 << 3) /** Provide bubblebabble representation for DS RR's as comment */ -#define LDNS_COMMENT_BUBBLEBABBLE 0x0010 +#define LDNS_COMMENT_BUBBLEBABBLE (1 << 4) /** Show when a NSEC3 RR has the optout flag set as comment */ -#define LDNS_COMMENT_FLAGS 0x0020 +#define LDNS_COMMENT_FLAGS (1 << 5) /** Show the unhashed owner and next owner names for NSEC3 RR's as comment */ -#define LDNS_COMMENT_NSEC3_CHAIN 0x0040 +#define LDNS_COMMENT_NSEC3_CHAIN (1 << 6) /* yes */ /** Print mark up */ -#define LDNS_COMMENT_LAYOUT 0x0080 +#define LDNS_COMMENT_LAYOUT (1 << 7) /** Also comment KEY_ID with RRSIGS **/ -#define LDNS_COMMENT_RRSIGS 0x0100 -#define LDNS_FMT_ZEROIZE_RRSIGS 0x0200 -#define LDNS_FMT_PAD_SOA_SERIAL 0x0400 +#define LDNS_COMMENT_RRSIGS (1 << 8) +#define LDNS_FMT_ZEROIZE_RRSIGS (1 << 9) +#define LDNS_FMT_PAD_SOA_SERIAL (1 << 10) +#define LDNS_FMT_RFC3597 (1 << 11) /* yes */ + +#define LDNS_FMT_FLAGS_WITH_DATA 2 + +/** Show key id, type and size as comment for DNSKEY RR's */ +#define LDNS_COMMENT_KEY (LDNS_COMMENT_KEY_ID \ + |LDNS_COMMENT_KEY_TYPE\ + |LDNS_COMMENT_KEY_SIZE) /** * Output format specifier @@ -86,6 +92,18 @@ struct ldns_struct_output_format }; typedef struct ldns_struct_output_format ldns_output_format; +/** + * Output format struct with additional data for flags that use them. + * This struct may not be initialized directly. Use ldns_output_format_init + * to initialize. + */ +struct ldns_struct_output_format_storage +{ int flags; + ldns_rbtree_t* hashmap; /* for LDNS_FMT_NSEC3_CHAIN */ + ldns_rdf* bitmap; /* for LDNS_FMT_RFC3597 */ +}; +typedef struct ldns_struct_output_format_storage ldns_output_format_storage; + /** * Standard output format record that disables commenting in the textual * representation of Resource Records completely. @@ -107,6 +125,55 @@ extern const ldns_output_format *ldns_output_format_default; */ extern const ldns_output_format *ldns_output_format_bubblebabble; +/** + * Initialize output format storage to the default value. + * \param[in] fmt A reference to an output_format_ storage struct + * \return The initialized storage struct typecasted to ldns_output_format + */ +INLINE +ldns_output_format* ldns_output_format_init(ldns_output_format_storage* fmt) { + fmt->flags = ldns_output_format_default->flags; + fmt->hashmap = NULL; + fmt->bitmap = NULL; + return (ldns_output_format*)fmt; +} + +/** + * Set an ouput format flag. + */ +INLINE void ldns_output_format_set(ldns_output_format* fmt, int flag) { + fmt->flags |= flag; +} + +/** + * Clear an ouput format flag. + */ +INLINE void ldns_output_format_clear(ldns_output_format* fmt, int flag) { + fmt->flags &= !flag; +} + +/** + * Makes sure the LDNS_FMT_RFC3597 is set in the output format. + * Marks the type to be printed in RFC3597 format. + * /param[in] fmt the output format to update + * /param[in] the type to be printed in RFC3597 format + * /return LDNS_STATUS_OK on success + */ +ldns_status +ldns_output_format_set_type(ldns_output_format* fmt, ldns_rr_type type); + +/** + * Makes sure the LDNS_FMT_RFC3597 is set in the output format. + * Marks the type to not be printed in RFC3597 format. When no other types + * have been marked before, all known types (except the given one) will be + * marked for printing in RFC3597 format. + * /param[in] fmt the output format to update + * /param[in] the type not to be printed in RFC3597 format + * /return LDNS_STATUS_OK on success + */ +ldns_status +ldns_output_format_clear_type(ldns_output_format* fmt, ldns_rr_type type); + /** * Converts an ldns packet opcode value to its mnemonic, and adds that * to the output buffer diff --git a/ldns/rdata.h b/ldns/rdata.h index 70131798..8f7be8c2 100644 --- a/ldns/rdata.h +++ b/ldns/rdata.h @@ -135,7 +135,10 @@ enum ldns_enum_rdf_type * maximum length of 255 octets. * For URI. */ - LDNS_RDF_TYPE_MULTI_STR + LDNS_RDF_TYPE_MULTI_STR, + + /* Aliases */ + LDNS_RDF_TYPE_BITMAP = LDNS_RDF_TYPE_NSEC }; typedef enum ldns_enum_rdf_type ldns_rdf_type; diff --git a/ldns/rr.h b/ldns/rr.h index 7d90a734..1485cadf 100644 --- a/ldns/rr.h +++ b/ldns/rr.h @@ -359,6 +359,23 @@ struct ldns_struct_rr_descriptor }; typedef struct ldns_struct_rr_descriptor ldns_rr_descriptor; + +/** + * Create a rr type bitmap rdf providing enough space to set all + * known (to ldns) rr types. + * \param[out] rdf the constructed rdf + * \return LDNS_STATUS_OK if all went well. + */ +ldns_status ldns_rdf_bitmap_known_rr_types_space(ldns_rdf** rdf); + +/** + * Create a rr type bitmap rdf with at least all known (to ldns) rr types set. + * \param[out] rdf the constructed rdf + * \return LDNS_STATUS_OK if all went well. + */ +ldns_status ldns_rdf_bitmap_known_rr_types(ldns_rdf** rdf); + + /** * creates a new rr structure. * \return ldns_rr * diff --git a/rr.c b/rr.c index 2ec02e81..eae1f3af 100644 --- a/rr.c +++ b/rr.c @@ -2380,6 +2380,125 @@ static ldns_rr_descriptor rdata_field_descriptors[] = { #define LDNS_RDATA_FIELD_DESCRIPTORS_COUNT \ (sizeof(rdata_field_descriptors)/sizeof(rdata_field_descriptors[0])) + +/*---------------------------------------------------------------------------* + * The functions below return an bitmap RDF with the space required to set + * or unset all known RR types. Arguably these functions are better situated + * in rdata.c, however for the space calculation it is necesarry to walk + * through rdata_field_descriptors which is not easily possible from anywhere + * other than rr.c where it is declared static. + * + * Alternatively rr.c could have provided an iterator for rr_type or + * rdf_descriptors, but this seemed overkill for internal use only. + */ +static ldns_rr_descriptor* rdata_field_descriptors_end = + &rdata_field_descriptors[LDNS_RDATA_FIELD_DESCRIPTORS_COUNT]; + +/* From RFC3845: + * + * 2.1.2. The List of Type Bit Map(s) Field + * + * The RR type space is split into 256 window blocks, each representing + * the low-order 8 bits of the 16-bit RR type space. Each block that + * has at least one active RR type is encoded using a single octet + * window number (from 0 to 255), a single octet bitmap length (from 1 + * to 32) indicating the number of octets used for the window block's + * bitmap, and up to 32 octets (256 bits) of bitmap. + * + * Window blocks are present in the NSEC RR RDATA in increasing + * numerical order. + * + * "|" denotes concatenation + * + * Type Bit Map(s) Field = ( Window Block # | Bitmap Length | Bitmap ) + + * + * + * + * Blocks with no types present MUST NOT be included. Trailing zero + * octets in the bitmap MUST be omitted. The length of each block's + * bitmap is determined by the type code with the largest numerical + * value within that block, among the set of RR types present at the + * NSEC RR's owner name. Trailing zero octets not specified MUST be + * interpreted as zero octets. + */ +static ldns_status +ldns_rdf_bitmap_known_rr_types_set(ldns_rdf** rdf, int value) +{ + uint8_t window; /* most significant octet of type */ + uint8_t subtype; /* least significant octet of type */ + uint16_t windows[256] /* Max subtype per window */ +#ifndef S_SPLINT_S + = { 0 } +#endif + ; + ldns_rr_descriptor* d; /* used to traverse rdata_field_descriptors */ + size_t i; /* used to traverse windows array */ + + size_t sz; /* size needed for type bitmap rdf */ + uint8_t* data = NULL; /* rdf data */ + uint8_t* dptr; /* used to itraverse rdf data */ + + assert(rdf != NULL); + + /* Which windows need to be in the bitmap rdf? + */ + for (d=rdata_field_descriptors; d < rdata_field_descriptors_end; d++) { + window = d->_type >> 8; + subtype = d->_type & 0xff; + if (windows[window] < subtype) { + windows[window] = subtype; + } + } + + /* How much space do we need in the rdf for those windows? + */ + sz = 0; + for (i = 0; i < 256; i++) { + if (windows[i]) { + sz += windows[i] / 8 + 3; + } + } + if (sz > 0) { + /* Format rdf data according RFC3845 Section 2.1.2 (see above) + */ + dptr = data = LDNS_XMALLOC(uint8_t, sz); + if (!data) { + return LDNS_STATUS_MEM_ERR; + } + for (i = 0; i < 256; i++) { + if (windows[i]) { + *dptr++ = (uint8_t)i; + *dptr++ = (uint8_t)(windows[i] / 8 + 1); + memset(dptr, value, dptr[-1]); + dptr += dptr[-1]; + } + } + } + /* Allocate and return rdf structure for the data + */ + *rdf = ldns_rdf_new(LDNS_RDF_TYPE_BITMAP, sz, data); + if (!*rdf) { + LDNS_FREE(data); + return LDNS_STATUS_MEM_ERR; + } + return LDNS_STATUS_OK; +} + +ldns_status +ldns_rdf_bitmap_known_rr_types_space(ldns_rdf** rdf) +{ + return ldns_rdf_bitmap_known_rr_types_set(rdf, 0); +} + +ldns_status +ldns_rdf_bitmap_known_rr_types(ldns_rdf** rdf) +{ + return ldns_rdf_bitmap_known_rr_types_set(rdf, 255); +} +/* End of RDF bitmap functions + *---------------------------------------------------------------------------*/ + + const ldns_rr_descriptor * ldns_rr_descript(uint16_t type) {